diff --git a/Client/WebServer/Images/sa-beta9-logo-horiz-dark.png b/Client/WebServer/Images/sa-beta9-logo-horiz-dark.png new file mode 100644 index 000000000..b7121cbad Binary files /dev/null and b/Client/WebServer/Images/sa-beta9-logo-horiz-dark.png differ diff --git a/Client/client.js b/Client/client.js index c6e34dff9..f32434bc8 100644 --- a/Client/client.js +++ b/Client/client.js @@ -127,12 +127,12 @@ try { console.log('Http Interface ..................... Listening at port ' + global.env.HTTP_INTERFACE_PORT) console.log('') - console.log("You are running Superalgos Beta 8") + console.log("You are running Superalgos Beta 9") console.log('') console.log("What's new? The following was implemented here:") console.log('') - console.log('Task Server Upgraded ............... This allow us to integrate crypto projects into the Task Server, opening the door to new types of bots defined at other projects.') - console.log('In-App Documentation Improved ...... This allow users to improve the docs / tutorials, correcting, expanding and translating pages.') + console.log('Merket Data Structure .............. This allows any strategy to use data from markets different from the one it is running at.') + console.log('Exchange Data Structure ............ This allows any strategy to use data from exchanges and markets different from the one it is running at.') console.log('') console.log("What's next? At the development pipeline we have:") console.log('') diff --git a/Client/httpInterface.js b/Client/httpInterface.js index c9db7f9f4..9dcef15a7 100644 --- a/Client/httpInterface.js +++ b/Client/httpInterface.js @@ -675,7 +675,7 @@ exports.newHttpInterface = function newHttpInterface(WEB_SERVER, DATA_FILE_SERVE const octokit = new Octokit({ auth: token, - userAgent: 'Superalgos Beta 8' + userAgent: 'Superalgos Beta 9' }) const repo = 'Superalgos' diff --git a/Projects/Superalgos/Schemas/AppSchema.json b/Projects/Superalgos/Schemas/AppSchema.json index b509ef075..50e348b90 100644 --- a/Projects/Superalgos/Schemas/AppSchema.json +++ b/Projects/Superalgos/Schemas/AppSchema.json @@ -11580,7 +11580,7 @@ }, "level": 4, "attachingRules": { - "compatibleTypes": "->Target Size In Base Asset->Target Size In Quoted Asset->Target Rate->Phase->Simulated Actual Rate->Situation->Indicator Function->" + "compatibleTypes": "->Target Size In Base Asset->Target Size In Quoted Asset->Target Rate->Phase->Simulated Actual Rate->Situation->Indicator Function->Order Rate->" }, "propertyNameAtParent": "formula" }, diff --git a/Projects/Superalgos/Schemas/Docs-Concepts/default-exchange.json b/Projects/Superalgos/Schemas/Docs-Concepts/default-exchange.json new file mode 100644 index 000000000..da0550999 --- /dev/null +++ b/Projects/Superalgos/Schemas/Docs-Concepts/default-exchange.json @@ -0,0 +1,13 @@ +{ + "type": "Default Exchange", + "definition": { + "text": "The Default Exchange is the one referenced by the Exchange Data Tasks, Exchange Trading Tasks, Exchange Learning Tasks nodes of which a certain Task decends from. The Trading Bot running inside that Task will considere that referenced exchange to be it's Default Exchange.", + "updated": 1612352828045 + }, + "paragraphs": [ + { + "style": "Text", + "text": "Left click and Edit to enter edit mode and change this text. ENTER to write new paragraphs. ESC to exit edit mode. Then you can use doscs.save to save your changes and app.contribute to send it to the main repository." + } + ] +} \ No newline at end of file diff --git a/Projects/Superalgos/Schemas/Docs-Concepts/default-market.json b/Projects/Superalgos/Schemas/Docs-Concepts/default-market.json new file mode 100644 index 000000000..8415e1960 --- /dev/null +++ b/Projects/Superalgos/Schemas/Docs-Concepts/default-market.json @@ -0,0 +1,13 @@ +{ + "type": "Default Market", + "definition": { + "text": "The Default Market is the one referenced by the Market Data Tasks, Market Trading Tasks, Market Learning Tasks nodes of which a certain Task decends from. The Trading Bot running inside that Task will considered that reference market to be it's Default Market.", + "updated": 1612352846165 + }, + "paragraphs": [ + { + "style": "Text", + "text": "Left click and Edit to enter edit mode and change this text. ENTER to write new paragraphs. ESC to exit edit mode. Then you can use doscs.save to save your changes and app.contribute to send it to the main repository." + } + ] +} \ No newline at end of file diff --git a/Projects/Superalgos/Schemas/Docs-Topics/lf-trading-bot-available-data-structures-001-lf-trading-bot-chart-data-structure.json b/Projects/Superalgos/Schemas/Docs-Topics/lf-trading-bot-available-data-structures-001-lf-trading-bot-chart-data-structure.json new file mode 100644 index 000000000..35244ad83 --- /dev/null +++ b/Projects/Superalgos/Schemas/Docs-Topics/lf-trading-bot-available-data-structures-001-lf-trading-bot-chart-data-structure.json @@ -0,0 +1,101 @@ +{ + "topic": "LF Trading Bot Available Data Structures", + "pageNumber": "1", + "type": "LF Trading Bot - Chart Data Structure", + "definition": { + "text": "The Chart Data Structure is an object that contains Indicator or Sensor bots data, available at runtime, that can be accessed from the code of Conditions and Formulas.", + "updated": 1612349390525 + }, + "paragraphs": [ + { + "style": "Note", + "text": "This Javascript object, together with the other two data structures available, ultimately defines the syntax that can be used to write conditions and formulas, and more precisely the sintax to retrieve Indicator Bot and Sensor Bot data.", + "updated": 1612349521002 + }, + { + "style": "Title", + "text": "Structure" + }, + { + "style": "List", + "text": "The root of the object is called...", + "updated": 1612351077417 + }, + { + "style": "Json", + "text": "chart" + }, + { + "style": "List", + "text": "After it these are it's valid properties...", + "updated": 1612351085368 + }, + { + "style": "Json", + "text": "at01min, at02min ... at45min, at01hs ... at24hs", + "updated": 1612349768772 + }, + { + "style": "List", + "text": "After that, it is expected the singleVariableName defined at the config of the Product Definition of an Indicator or Sensor.", + "updated": 1612351093008 + }, + { + "style": "List", + "text": "Finally the last property must be the codeName of a Record Property Node, belonging to the same Product Definition mentioned earlier.", + "updated": 1612350081190 + }, + { + "style": "Title", + "text": "Examples", + "updated": 1612350235632 + }, + { + "style": "Text", + "text": "chart.at01min.support.support5Rate", + "updated": 1612349808636 + }, + { + "style": "Text", + "text": "chart.at05min.candle.open", + "updated": 1612350213519 + }, + { + "style": "Text", + "text": "chart.at24hs.bollingerBand.movingAverage" + }, + { + "style": "Title", + "text": "Advance Usage" + }, + { + "style": "Text", + "text": "You also have access to the set of indicators objects loaded in memory though this same data structure. If instead of using the sinleVariableName you use the pluralVariableName what you get is an array of objects, that depending on the time frame, could be the object for that time frame of all market or the current and previous day for time frames < 1 hour.", + "updated": 1612353614216 + }, + { + "style": "Title", + "text": "Examples" + }, + { + "style": "Text", + "text": "chart.at05min.candles" + }, + { + "style": "Text", + "text": "Will return an array of candles of the previous day concatenated with the candles of the current day. You then can use this information as you wish." + }, + { + "style": "Text", + "text": "chart.at24hs.bollingerBands" + }, + { + "style": "Text", + "text": "Will return an array of all bollingerBands object of the whole market, since the time frame is >= 1 hour." + }, + { + "style": "Text", + "text": "" + } + ] +} \ No newline at end of file diff --git a/Projects/Superalgos/Schemas/Docs-Topics/lf-trading-bot-available-data-structures-002-lf-trading-bot-market-data-structure.json b/Projects/Superalgos/Schemas/Docs-Topics/lf-trading-bot-available-data-structures-002-lf-trading-bot-market-data-structure.json new file mode 100644 index 000000000..cdd0ec5bd --- /dev/null +++ b/Projects/Superalgos/Schemas/Docs-Topics/lf-trading-bot-available-data-structures-002-lf-trading-bot-market-data-structure.json @@ -0,0 +1,72 @@ +{ + "topic": "LF Trading Bot Available Data Structures", + "pageNumber": "2", + "type": "LF Trading Bot - Market Data Structure", + "definition": { + "text": "The Market Data Structure is one of the 3 data structures available at Conditions and Formulas with data from Indicator and Sensor bots.", + "updated": 1612351166683 + }, + "paragraphs": [ + { + "style": "Note", + "text": "This Javascript object can be used when you want to specify a market which is different fomr the Default Market. In this way you can access data of the ETH/USDT market from a stragegy running for example at the BTC/USDT market.", + "updated": 1612351365558 + }, + { + "style": "Title", + "text": "Structure" + }, + { + "style": "List", + "text": "The root of the object is called..." + }, + { + "style": "Json", + "text": "market", + "updated": 1612351449944 + }, + { + "style": "List", + "text": "After it you need to spacify the codeName of an Asset representing the Market Base Asset, like the following...", + "updated": 1612351559165 + }, + { + "style": "Json", + "text": "BTC, USDT, ETH... etc.", + "updated": 1612351687073 + }, + { + "style": "List", + "text": "After that again the codeName of an Asset but this time representing the Market Quoted Asset.." + }, + { + "style": "Json", + "text": "BTC, USDT, ETH... etc." + }, + { + "style": "List", + "text": "Finally you continue with the syntax of the LF Trading Bot - Chart Data Structure", + "updated": 1612352138708 + }, + { + "style": "Title", + "text": "Examples", + "updated": 1612352364588 + }, + { + "style": "Text", + "text": "market.ETH.BTC.chart.at01min.support.support5Rate", + "updated": 1612351751906 + }, + { + "style": "Text", + "text": "market.BTC.USDT.chart.at05min.candle.open", + "updated": 1612351782297 + }, + { + "style": "Text", + "text": "market.ETH.USDT.chart.at24hs.bollingerBand.movingAverage", + "updated": 1612351804074 + } + ] +} \ No newline at end of file diff --git a/Projects/Superalgos/Schemas/Docs-Topics/lf-trading-bot-available-data-structures-003-lf-trading-bot-exchange-data-structure.json b/Projects/Superalgos/Schemas/Docs-Topics/lf-trading-bot-available-data-structures-003-lf-trading-bot-exchange-data-structure.json new file mode 100644 index 000000000..69d6eec72 --- /dev/null +++ b/Projects/Superalgos/Schemas/Docs-Topics/lf-trading-bot-available-data-structures-003-lf-trading-bot-exchange-data-structure.json @@ -0,0 +1,77 @@ +{ + "topic": "LF Trading Bot Available Data Structures", + "pageNumber": "3", + "type": "LF Trading Bot - Exchange Data Structure", + "definition": { + "text": "Write a summary for this topic page." + }, + "paragraphs": [ + { + "style": "Note", + "text": "This Javascript object can be used when you want to specify a Cryto Exchage which is different fomr the Default Exchange. In this way you can access data from Coinbase Pro from a stragegy running for example at Binance.", + "updated": 1612351988656 + }, + { + "style": "Title", + "text": "Structure" + }, + { + "style": "List", + "text": "The root of the object is called..." + }, + { + "style": "Json", + "text": "exchange", + "updated": 1612352008621 + }, + { + "style": "List", + "text": "After it you need to spacify the codeName of a Crypto Exchange, like the following...", + "updated": 1612352057634 + }, + { + "style": "Json", + "text": "biance, bitfinex, coinbasepro... etc.", + "updated": 1612352082792 + }, + { + "style": "List", + "text": "Finally you continue with the syntax of the LF Trading Bot - Market Data Structure", + "updated": 1612352124926 + }, + { + "style": "Title", + "text": "Examples", + "updated": 1612352354839 + }, + { + "style": "Text", + "text": "exchange.poloniex.market.ETH.BTC.chart.at01min.support.support5Rate", + "updated": 1612352167087 + }, + { + "style": "Text", + "text": "exchange.bitfinex.market.BTC.USDT.chart.at05min.candle.open", + "updated": 1612352188098 + }, + { + "style": "Text", + "text": "exchange.binance.market.ETH.USDT.chart.at24hs.bollingerBand.movingAverage", + "updated": 1612352200136 + }, + { + "style": "Title", + "text": "Formula Example", + "updated": 1612352272503 + }, + { + "style": "Text", + "text": "As you can see at the following example you can have a mix of chart, market and exchange usage withing the same Formula or Condition. " + }, + { + "style": "Json", + "text": "chart.at01min.support.support5Rate +\nexchange.poloniex.market.ETH.USDT.chart.at05min.candle.close", + "updated": 1612352290634 + } + ] +} \ No newline at end of file diff --git a/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/Bollinger-Bands/BollingerBandsMultiPeriodDaily.js b/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/Bollinger-Bands/BollingerBandsMultiPeriodDaily.js index b00255d6e..726ed72cd 100644 --- a/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/Bollinger-Bands/BollingerBandsMultiPeriodDaily.js +++ b/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/Bollinger-Bands/BollingerBandsMultiPeriodDaily.js @@ -349,7 +349,7 @@ TS.projects.superalgos.globals.taskConstants.PROJECT_DEFINITION_NODE.config.codeName + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.type.replace(' ', '-') + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "/" + - "Candles-Volumes" + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "/" + + "Candles-Volumes" + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + '/' + "Multi-Period-Daily" + "/" + timeFrame + "/" + dateForPath; @@ -395,7 +395,7 @@ TS.projects.superalgos.globals.taskConstants.PROJECT_DEFINITION_NODE.config.codeName + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.type.replace(' ', '-') + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "/" + - "Candles-Volumes" + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "/" + + "Candles-Volumes" + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + '/' + "Multi-Period-Daily" + "/" + timeFrame + "/" + dateForPath; diff --git a/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/Bollinger-Bands/BollingerBandsMultiPeriodMarket.js b/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/Bollinger-Bands/BollingerBandsMultiPeriodMarket.js index 6ff41f11b..9e3d81aad 100644 --- a/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/Bollinger-Bands/BollingerBandsMultiPeriodMarket.js +++ b/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/Bollinger-Bands/BollingerBandsMultiPeriodMarket.js @@ -70,7 +70,7 @@ 'Project/' + TS.projects.superalgos.globals.taskConstants.PROJECT_DEFINITION_NODE.config.codeName + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.type.replace(' ', '-') + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "/" + - "Candles-Volumes" + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "/" + + "Candles-Volumes" + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timeFrame; diff --git a/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/Candles-Volumes/CandlesVolumesMultiPeriodDaily.js b/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/Candles-Volumes/CandlesVolumesMultiPeriodDaily.js index d8a666447..ed9686b0d 100644 --- a/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/Candles-Volumes/CandlesVolumesMultiPeriodDaily.js +++ b/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/Candles-Volumes/CandlesVolumesMultiPeriodDaily.js @@ -301,7 +301,7 @@ TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.type.replace(' ', '-') + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "/" + "Exchange-Raw-Data" + '/' + - TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "/" + + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + '/' + CANDLES_ONE_MIN + '/' + dateForPath @@ -422,7 +422,7 @@ TS.projects.superalgos.globals.taskConstants.PROJECT_DEFINITION_NODE.config.codeName + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.type.replace(' ', '-') + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "/" + - "Exchange-Raw-Data" + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "/" + + "Exchange-Raw-Data" + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName let filePath = @@ -709,7 +709,7 @@ TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.config.codeName + "-" + pProductFolder + "-" + - TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "-" + + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName let event = { diff --git a/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/Candles-Volumes/CandlesVolumesMultiPeriodMarket.js b/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/Candles-Volumes/CandlesVolumesMultiPeriodMarket.js index 958dee176..3bf3bb8e9 100644 --- a/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/Candles-Volumes/CandlesVolumesMultiPeriodMarket.js +++ b/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/Candles-Volumes/CandlesVolumesMultiPeriodMarket.js @@ -521,7 +521,7 @@ TS.projects.superalgos.globals.taskConstants.PROJECT_DEFINITION_NODE.config.codeName + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.type.replace(' ', '-') + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "/" + - "Exchange-Raw-Data" + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "/" + + "Exchange-Raw-Data" + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + '/' + CANDLES_ONE_MIN + '/' + dateForPath; @@ -648,7 +648,7 @@ TS.projects.superalgos.globals.taskConstants.PROJECT_DEFINITION_NODE.config.codeName + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.type.replace(' ', '-') + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "/" + - "Exchange-Raw-Data" + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "/" + + "Exchange-Raw-Data" + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName let filePath = filePathRoot + "/Output/" + VOLUMES_FOLDER_NAME + '/' + VOLUMES_ONE_MIN + '/' + dateForPath; diff --git a/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/MultiPeriodDaily.js b/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/MultiPeriodDaily.js index c4ed56b43..99acc71f5 100644 --- a/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/MultiPeriodDaily.js +++ b/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/MultiPeriodDaily.js @@ -328,7 +328,7 @@ dependencyLoopBody() function dependencyLoopBody() { - let dependency = dataDependenciesModule.nodeArray[dependencyIndex] + let dependency = dataDependenciesModule.curatedDependencyNodeArray[dependencyIndex] if (dependency === undefined) { TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, @@ -453,7 +453,7 @@ function dependencyControlLoop() { dependencyIndex++; - if (dependencyIndex < dataDependenciesModule.nodeArray.length) { + if (dependencyIndex < dataDependenciesModule.curatedDependencyNodeArray.length) { dependencyLoopBody() } else { generateOutput() @@ -549,7 +549,7 @@ } let key = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.config.codeName + "-" + productCodeName + "-" + - TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "-" + + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName let event = { diff --git a/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/MultiPeriodMarket.js b/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/MultiPeriodMarket.js index 120bdfef1..6dd051d6b 100644 --- a/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/MultiPeriodMarket.js +++ b/Projects/Superalgos/TS/Bot-Modules/Indicator-Bot/MultiPeriodMarket.js @@ -68,7 +68,7 @@ dependencyLoopBody() function dependencyLoopBody() { - let dependency = dataDependenciesModule.nodeArray[dependencyIndex] + let dependency = dataDependenciesModule.curatedDependencyNodeArray[dependencyIndex] let datasetModule = dataDependenciesModule.dataSetsModulesArray[dependencyIndex] getFile() @@ -96,7 +96,7 @@ function dependencyControlLoop() { dependencyIndex++; - if (dependencyIndex < dataDependenciesModule.nodeArray.length) { + if (dependencyIndex < dataDependenciesModule.curatedDependencyNodeArray.length) { dependencyLoopBody() } else { generateOutput() diff --git a/Projects/Superalgos/TS/Bot-Modules/Sensor-Bot/Exchange-Raw-Data/HistoricOHLCVs.js b/Projects/Superalgos/TS/Bot-Modules/Sensor-Bot/Exchange-Raw-Data/HistoricOHLCVs.js index eabe00757..16e37a46a 100644 --- a/Projects/Superalgos/TS/Bot-Modules/Sensor-Bot/Exchange-Raw-Data/HistoricOHLCVs.js +++ b/Projects/Superalgos/TS/Bot-Modules/Sensor-Bot/Exchange-Raw-Data/HistoricOHLCVs.js @@ -43,7 +43,7 @@ exports.newSuperalgosBotModulesHistoricOHLCVs = function (processIndex) { try { statusDependencies = pStatusDependencies; - exchangeId = TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name.toLowerCase().replace(' ', '') + exchangeId = TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName /* Applying the parameters defined by the user at the Exchange Node Config */ if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.API !== undefined) { diff --git a/Projects/Superalgos/TS/Bot-Modules/Sensor-Bot/Webhooks/CheckWebhook.js b/Projects/Superalgos/TS/Bot-Modules/Sensor-Bot/Webhooks/CheckWebhook.js index f005f8ee7..261576ef9 100644 --- a/Projects/Superalgos/TS/Bot-Modules/Sensor-Bot/Webhooks/CheckWebhook.js +++ b/Projects/Superalgos/TS/Bot-Modules/Sensor-Bot/Webhooks/CheckWebhook.js @@ -93,7 +93,7 @@ exports.newSuperalgosBotModulesCheckWebhook = function (processIndex) { let url = 'http://' + global.env.WEB_SERVER_URL + ':' + global.env.HTTP_INTERFACE_PORT + '/Webhook/Fetch-Messages/' + - TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "/" + + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/ExchangeAPI.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/ExchangeAPI.js index 4961f5091..65e427db7 100644 --- a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/ExchangeAPI.js +++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/ExchangeAPI.js @@ -23,7 +23,7 @@ function initialize() { tradingSystem = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE.tradingSystem - exchangeId = TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name.toLowerCase() + exchangeId = TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName let key let secret diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/Snapshots.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/Snapshots.js index 4af1bcfbd..031eab5d9 100644 --- a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/Snapshots.js +++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/Snapshots.js @@ -38,7 +38,13 @@ exports.newSuperalgosBotModulesSnapshots = function (processIndex) { let positionValues let addToPositionValues + /* + These 3 are the main data structures available to users + when writing conditions and formulas. + */ let chart + let exchange + let market return thisObject @@ -58,10 +64,18 @@ exports.newSuperalgosBotModulesSnapshots = function (processIndex) { strategyKeys = undefined chart = undefined + exchange = undefined + market = undefined } - function updateChart(pChart) { + function updateChart(pChart, pExchange, pMarket) { + /* + We need these 3 data structures to be a local objects + accessible while evaluating conditions and formulas. + */ chart = pChart + exchange = pExchange + market = pMarket } function strategyEntry() { diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingOutput.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingOutput.js index c6b2f28ca..d0a799b9a 100644 --- a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingOutput.js +++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingOutput.js @@ -26,7 +26,14 @@ exports.newSuperalgosBotModulesTradingOutput = function (processIndex) { } - async function start(chart, timeFrame, timeFrameLabel, tradingProcessDate) { + async function start( + chart, + market, + exchange, + timeFrame, + timeFrameLabel, + tradingProcessDate + ) { try { if (timeFrame > TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[0][0]) { @@ -73,6 +80,8 @@ exports.newSuperalgosBotModulesTradingOutput = function (processIndex) { await tradingSimulationModuleObject.runSimulation( chart, + market, + exchange, outputDatasetsMap, writeFiles ) diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingProcess.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingProcess.js index 6c8f56339..edcee3374 100644 --- a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingProcess.js +++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingProcess.js @@ -14,12 +14,12 @@ let statusDependencies let dataDependenciesModule let dataFiles = new Map() - let multiPeriodDataFiles = new Map() + let multiTimeFrameDataFiles = new Map() let fileStorage = TS.projects.superalgos.taskModules.fileStorage.newFileStorage(processIndex) TS.projects.superalgos.globals.processModuleObjects.MODULE_OBJECTS_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_ENGINE_MODULE_OBJECT = TS.projects.superalgos.botModules.tradingEngine.newSuperalgosBotModulesTradingEngine(processIndex) let tradingOutputModuleObject = TS.projects.superalgos.botModules.tradingOutput.newSuperalgosBotModulesTradingOutput(processIndex) - return thisObject; + return thisObject function initialize(pStatusDependencies, pDataDependencies, callBackFunction) { try { @@ -33,7 +33,7 @@ } catch (err) { TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, - "[ERROR] initialize -> err = " + err.stack); + "[ERROR] initialize -> err = " + err.stack) callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE) } } @@ -47,7 +47,7 @@ tradingOutputModuleObject = undefined dataFiles = undefined - multiPeriodDataFiles = undefined + multiTimeFrameDataFiles = undefined statusDependencies = undefined dataDependenciesModule = undefined fileStorage = undefined @@ -64,7 +64,7 @@ lastFile: undefined, // Datetime of the last file files successfully produced by this process. dateBeginOfMarket: undefined, // Datetime of the first trade file in the whole market history. dateEndOfMarket: undefined // Datetime of the last file available to be used as an input of this process. - }; + } if (getContextVariables() !== true) { return } @@ -115,10 +115,11 @@ return } /* - This is the Data Structure used at the Simulation with all indicator data. - We start creating it right here. + These are the Data Structures used by end users at Conditions Code or Formulas. */ let chart = {} + let market = {} + let exchange = {} /* Here we check if we need to get Daily Files or not. As an optimization, when we are running on a Time Frame of 1hs or above, we are not going to load @@ -133,11 +134,11 @@ data structure that will be used in user-defied conditions and formulas. */ TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Waking up') - buildCharts(chart) + buildDataStructures() - if (checkThereAreCandles(chart) === true) { + if (checkThereAreCandles() === true) { TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Running') - await generateOutput(chart) + await generateOutput() TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Saving') await writeProcessFiles() TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Sleeping') @@ -172,13 +173,13 @@ With all the indicators data files loaded, we will build the chart object data structure that will be used in user-defied conditions and formulas. */ - buildCharts(chart) + buildDataStructures() /* The process of generating the output includes the trading simulation. */ - if (checkThereAreCandles(chart) === true) { + if (checkThereAreCandles() === true) { TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Running') - await generateOutput(chart) + await generateOutput() TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Saving') await writeProcessFiles() TS.projects.superalgos.functionLibraries.sessionFunctions.sessionHeartBeat(processIndex, undefined, undefined, 'Sleeping') @@ -209,7 +210,7 @@ */ callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE) - function checkThereAreCandles(chart) { + function checkThereAreCandles() { let sessionParameters = TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters let propertyName = 'at' + sessionParameters.timeFrame.config.label.replace('-', '') let candles = chart[propertyName].candles @@ -223,8 +224,8 @@ function getContextVariables() { try { - let thisReport; - let statusReport; + let thisReport + let statusReport /* We are going to use the start date as beging of market date. */ contextVariables.dateBeginOfMarket = TS.projects.superalgos.utilities.dateTimeFunctions.removeTime(TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeRange.config.initialDatetime) @@ -235,65 +236,65 @@ if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month. TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, - "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. "); - callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE); + "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ") + callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE) return false } if (statusReport.status === "Status Report is corrupt.") { TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, - "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. "); - callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE); + "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ") + callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE) return false } - thisReport = statusReport.file; + thisReport = statusReport.file if (thisReport.lastFile === undefined) { TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, - "[WARN] start -> getContextVariables -> Undefined Last File. -> thisReport = " + JSON.stringify(thisReport)); + "[WARN] start -> getContextVariables -> Undefined Last File. -> thisReport = " + JSON.stringify(thisReport)) let customOK = { result: TS.projects.superalgos.globals.standardResponses.CUSTOM_OK_RESPONSE.result, message: "Dependency not ready." } TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, - "[WARN] start -> getContextVariables -> customOK = " + customOK.message); - callBackFunction(customOK); + "[WARN] start -> getContextVariables -> customOK = " + customOK.message) + callBackFunction(customOK) return false } - contextVariables.dateEndOfMarket = new Date(thisReport.lastFile.valueOf()); + contextVariables.dateEndOfMarket = new Date(thisReport.lastFile.valueOf()) /* Finally we get our own Status Report. */ statusReport = statusDependencies.reportsByMainUtility.get("Self Reference") if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month. TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, - "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. "); - callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE); + "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ") + callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE) return false } if (statusReport.status === "Status Report is corrupt.") { TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, - "[ERROR] start -> getContextVariables -> Can not continue because self dependecy Status Report is corrupt. Aborting Process."); - callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE); + "[ERROR] start -> getContextVariables -> Can not continue because self dependecy Status Report is corrupt. Aborting Process.") + callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE) return false } - thisReport = statusReport.file; - TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE = thisReport.simulationState; + thisReport = statusReport.file + TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE = thisReport.simulationState if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE === undefined) { TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE = {} } // This should happen only when there is no status report if (thisReport.lastFile !== undefined) { if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).IS_SESSION_RESUMING !== true) { TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Starting from the begining because bot has just started and resume execution was true.") - startFromBegining(); + startFromBegining() return true } - contextVariables.lastFile = new Date(thisReport.lastFile); + contextVariables.lastFile = new Date(thisReport.lastFile) return true } else { @@ -304,12 +305,12 @@ */ TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Starting from the begining of the market because own status report not found or lastFile was undefined.") - startFromBegining(); + startFromBegining() return true } function startFromBegining() { - contextVariables.lastFile = new Date(contextVariables.dateBeginOfMarket.getUTCFullYear() + "-" + (contextVariables.dateBeginOfMarket.getUTCMonth() + 1) + "-" + contextVariables.dateBeginOfMarket.getUTCDate() + " " + "00:00" + TS.projects.superalgos.globals.timeConstants.GMT_SECONDS); + contextVariables.lastFile = new Date(contextVariables.dateBeginOfMarket.getUTCFullYear() + "-" + (contextVariables.dateBeginOfMarket.getUTCMonth() + 1) + "-" + contextVariables.dateBeginOfMarket.getUTCDate() + " " + "00:00" + TS.projects.superalgos.globals.timeConstants.GMT_SECONDS) TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[INFO] start -> getContextVariables -> startFromBegining -> contextVariables.lastFile = " + contextVariables.lastFile) @@ -318,222 +319,58 @@ } catch (err) { TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, - "[ERROR] start -> getContextVariables -> err = " + err.stack); + "[ERROR] start -> getContextVariables -> err = " + err.stack) if (err.message === "Cannot read property 'file' of undefined") { TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, - "[HINT] start -> getContextVariables -> Check the bot configuration to see if all of its statusDependencies declarations are correct. "); + "[HINT] start -> getContextVariables -> Check the bot configuration to see if all of its statusDependencies declarations are correct. ") TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, - "[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys)); + "[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys)) } - callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE); + callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE) } } async function processSingleFiles() { - dataFiles = new Map(); - for (let dependencyIndex = 0; dependencyIndex < dataDependenciesModule.nodeArray.length; dependencyIndex++) { - let dependency = dataDependenciesModule.nodeArray[dependencyIndex]; - let datasetModule = dataDependenciesModule.dataSetsModulesArray[dependencyIndex]; - - if (datasetModule.node.config.codeName !== "Single-File") { - continue - } - - if (dataDependenciesModule.isItADepenency('atAnyTimeFrame', datasetModule.node.parentNode.config.singularVariableName) !== true) { - continue - } - - let fileName = "Data.json"; - let filePath = datasetModule.node.parentNode.config.codeName + '/' + datasetModule.node.config.codeName; - - /* We cut the async calls via callBacks at this point, so as to have a clearer code upstream */ - let response = await asyncGetDatasetFile(datasetModule, filePath, fileName) - - if (response.err.message === 'File does not exist.') { - TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, - "[ERROR] File not Found. This process will wait until you run your Data Mining and this file is created. File = " + filePath + '/' + fileName) - TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, - "[ERROR] Your strategy depends on the dataset " + dependency.name + '.') - TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, - "[ERROR] The reason that it depends on this dataset is becuase in one of your condition's Javascript Code node, you have written an expression that references this dataset. If you don't want to depend on this dataset, just locate that code and remove the mention.") - return false - } - - if (response.err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) { - throw (response.err) - } - - let dataFile = JSON.parse(response.text); - dataFiles.set(dependency.id, dataFile); - } - - let mapKey = "Single Files" - multiPeriodDataFiles.set(mapKey, dataFiles) - } - - async function processMarketFiles() { /* - We do market files first since if the simulation is run on daily files, there will - be a loop to get each of those files and we do not need that loop to reload market files. - - We will iterate through all posible timeFrames. + We will iterate through all the exchanges and markets involved. */ - for (let n = 0; n < TS.projects.superalgos.globals.timeFrames.marketFilesPeriods().length; n++) { - const timeFrame = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][0]; - const timeFrameLabel = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][1]; + let exchangeList = Array.from(dataDependenciesModule.filters.exchange.list.keys()) + let marketList = Array.from(dataDependenciesModule.filters.market.list.keys()) - dataFiles = new Map(); + for (let e = 0; e < exchangeList.length; e++) { + let currentExchange = exchangeList[e] + for (let m = 0; m < marketList.length; m++) { + let currentMarket = marketList[m] - if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeFrame.config.label === timeFrameLabel) { - currentTimeFrame = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][0]; - currentTimeFrameLabel = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][1]; - } - for (let dependencyIndex = 0; dependencyIndex < dataDependenciesModule.nodeArray.length; dependencyIndex++) { - let dependency = dataDependenciesModule.nodeArray[dependencyIndex]; - let datasetModule = dataDependenciesModule.dataSetsModulesArray[dependencyIndex]; + dataFiles = new Map() - if (dependency.referenceParent.config.codeName !== "Multi-Period-Market") { - continue - } + for (let dependencyIndex = 0; dependencyIndex < dataDependenciesModule.curatedDependencyNodeArray.length; dependencyIndex++) { + let dependency = dataDependenciesModule.curatedDependencyNodeArray[dependencyIndex] + let datasetModule = dataDependenciesModule.dataSetsModulesArray[dependencyIndex] - if (dataDependenciesModule.isItADepenency(timeFrameLabel, datasetModule.node.parentNode.config.singularVariableName) !== true) { - if (!(TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeFrame.config.label === timeFrameLabel && datasetModule.node.parentNode.config.pluralVariableName === 'candles')) { + if (datasetModule.node.config.codeName !== "Single-File") { continue } - } - let fileName = "Data.json"; - let filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + timeFrameLabel; - - /* We cut the async calls via callBacks at this point, so as to have a clearer code upstream */ - let response = await asyncGetDatasetFile(datasetModule, filePath, fileName) - - if (response.err.message === 'File does not exist.') { - TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, - "[ERROR] File not Found. This process will wait until you run your Data Mining and this file is created. File = " + filePath + '/' + fileName) - TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, - "[ERROR] Your strategy depends on the dataset " + dependency.name + '.') - TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, - "[ERROR] The reason that it depends on this dataset is becuase in one of your condition's Javascript Code node, you have written an expression that references this dataset. If you don't want to depend on this dataset, just locate that code and remove the mention.") - return false - } - - if (response.err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) { - throw (response.err) - } - - let dataFile = JSON.parse(response.text); - let trimmedDataFile = trimDataFile(dataFile, datasetModule.node.parentNode.record) - dataFiles.set(dependency.id, trimmedDataFile); - - function trimDataFile(dataFile, recordDefinition) { - /* - Here we will discard all the records in a file that are outside of the current time range. - We will include the las element previous to the begining of the time range. This is needed - because during the simulation, the current period is not the open one, but the previous to - the open, and if we do not include the previous to the initial datetime there will be no - current objects at the begining of the simulation for many time frames. - */ - let beginIndex - let endIndex - let result = [] - for (let i = 0; i < recordDefinition.properties.length; i++) { - let property = recordDefinition.properties[i] - if (property.config.codeName === 'begin') { - beginIndex = i - } - if (property.config.codeName === 'end') { - endIndex = i - } - } - for (let i = 0; i < dataFile.length; i++) { - let dataRecord = dataFile[i] - let begin = dataRecord[beginIndex] - let end = dataRecord[endIndex] - if (end + timeFrame < TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeRange.config.initialDatetime - 1) { continue } // /1 because we need the previous closed element - if (begin > TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeRange.config.finalDatetime) { continue } - result.push(dataRecord) - } - return result - } - } - - let mapKey = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][1]; - multiPeriodDataFiles.set(mapKey, dataFiles) - } - return true - } - - async function processDailyFiles() { - /* Telling the world we are alive and doing well and which date we are processing right now. */ - let processingDateString = tradingProcessDate.getUTCFullYear() + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(tradingProcessDate.getUTCMonth() + 1, 2) + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(tradingProcessDate.getUTCDate(), 2); - TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, processingDateString, undefined, "Running...") - - /* - We will iterate through all posible timeFrames. - */ - for (let n = 0; n < TS.projects.superalgos.globals.timeFrames.dailyFilePeriods().length; n++) { - const timeFrame = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][0]; - const timeFrameLabel = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][1]; - - if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.framework.validtimeFrames !== undefined) { - let validPeriod = false; - for (let i = 0; i < TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.framework.validtimeFrames.length; i++) { - let period = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.framework.validtimeFrames[i]; - if (period === timeFrameLabel) { validPeriod = true } - } - if (validPeriod === false) { - continue - } - } - - if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeFrame.config.label === timeFrameLabel) { - currentTimeFrame = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][0]; - currentTimeFrameLabel = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][1]; - } - - dataFiles = new Map(); - - /* - We will iterate through all dependencies, in order to load the - files that later will end up at the chart data structure. - */ - for (let dependencyIndex = 0; dependencyIndex < dataDependenciesModule.nodeArray.length; dependencyIndex++) { - let dependency = dataDependenciesModule.nodeArray[dependencyIndex]; - let datasetModule = dataDependenciesModule.dataSetsModulesArray[dependencyIndex]; - - if (dependency.referenceParent.config.codeName !== "Multi-Period-Daily") { - continue - } - - /* - If it is not a dependency then we pass.. - */ - if (dataDependenciesModule.isItADepenency(timeFrameLabel, datasetModule.node.parentNode.config.singularVariableName) !== true) { - if (!(TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeFrame.config.label === timeFrameLabel && datasetModule.node.parentNode.config.pluralVariableName === 'candles')) { + if (datasetModule.exchange !== currentExchange) { continue } - } - /* - We will need to fetch the data of the current day and the previous day, in order for .previous properties in conditions and formulas to work well. - */ - let previousDate = new Date(tradingProcessDate.valueOf() - TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS) - let currentDate = new Date(tradingProcessDate.valueOf()) + if (datasetModule.market !== currentMarket) { + continue + } - let previousFile = await getDataFileFromDate(previousDate) - if (previousFile === false) { return false } - let currentFile = await getDataFileFromDate(currentDate) - if (currentFile === false) { return false } - let bothFiles = previousFile.concat(currentFile) - dataFiles.set(dependency.id, bothFiles) + if (dataDependenciesModule.filters.exchange.timeFrames.get(datasetModule.exchange + '-' + datasetModule.market + '-' + datasetModule.product + '-' + 'atAnyTimeFrame') !== true) { + /* + If we can not find the current data set is used at the current time + frame we will skip this file. + */ + continue + } - async function getDataFileFromDate(processDate) { - - let dateForPath = processDate.getUTCFullYear() + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(processDate.getUTCMonth() + 1, 2) + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(processDate.getUTCDate(), 2); - let filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + timeFrameLabel + "/" + dateForPath - let fileName = "Data.json"; + let fileName = "Data.json" + let filePath = datasetModule.node.parentNode.config.codeName + '/' + datasetModule.node.config.codeName /* We cut the async calls via callBacks at this point, so as to have a clearer code upstream */ let response = await asyncGetDatasetFile(datasetModule, filePath, fileName) @@ -547,15 +384,263 @@ "[ERROR] The reason that it depends on this dataset is becuase in one of your condition's Javascript Code node, you have written an expression that references this dataset. If you don't want to depend on this dataset, just locate that code and remove the mention.") return false } + if (response.err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) { throw (response.err) } - return JSON.parse(response.text) + let dataFile = JSON.parse(response.text) + dataFiles.set(dependency.id, dataFile) + } + + let mapKey = currentExchange + '-' + currentMarket + '-' + "Single Files" + multiTimeFrameDataFiles.set(mapKey, dataFiles) + } + } + } + + async function processMarketFiles() { + /* + We do market files first since if the simulation is run on daily files, there will + be a loop to get each of those files and we do not need that loop to reload market files. + */ + + /* + We will iterate through all the exchanges and markets involved. + */ + let exchangeList = Array.from(dataDependenciesModule.filters.exchange.list.keys()) + let marketList = Array.from(dataDependenciesModule.filters.market.list.keys()) + + for (let e = 0; e < exchangeList.length; e++) { + let currentExchange = exchangeList[e] + for (let m = 0; m < marketList.length; m++) { + let currentMarket = marketList[m] + /* + We will iterate through all posible timeFrames. + */ + for (let n = 0; n < TS.projects.superalgos.globals.timeFrames.marketFilesPeriods().length; n++) { + const timeFrame = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][0] + const timeFrameLabel = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][1] + + dataFiles = new Map() + + /* Current Time Frame detection */ + if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeFrame.config.label === timeFrameLabel) { + currentTimeFrame = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][0] + currentTimeFrameLabel = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][1] + } + + /* Loop across the list of curated dependencies */ + for (let dependencyIndex = 0; dependencyIndex < dataDependenciesModule.curatedDependencyNodeArray.length; dependencyIndex++) { + let dependency = dataDependenciesModule.curatedDependencyNodeArray[dependencyIndex] + let datasetModule = dataDependenciesModule.dataSetsModulesArray[dependencyIndex] + + if (dependency.referenceParent.config.codeName !== "Multi-Period-Market") { + continue + } + + if (datasetModule.exchange !== currentExchange) { + continue + } + + if (datasetModule.market !== currentMarket) { + continue + } + + if (dataDependenciesModule.filters.exchange.timeFrames.get(datasetModule.exchange + '-' + datasetModule.market + '-' + datasetModule.product + '-' + timeFrameLabel) !== true) { + /* + If we can not find the current data set is used at the current time + frame we will skip this file, unless we are in the only special + case that we are retrieving candles. + */ + if (!(TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeFrame.config.label === timeFrameLabel && datasetModule.node.parentNode.config.pluralVariableName === 'candles')) { + continue + } + if (currentExchange !== dataDependenciesModule.defaultExchange || currentMarket !== dataDependenciesModule.defaultMarket) { + continue + } + } + + let fileName = "Data.json" + let filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + timeFrameLabel + + /* We cut the async calls via callBacks at this point, so as to have a clearer code upstream */ + let response = await asyncGetDatasetFile(datasetModule, filePath, fileName) + + if (response.err.message === 'File does not exist.') { + TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, + "[ERROR] File not Found. This process will wait until you run your Data Mining and this file is created. File = " + filePath + '/' + fileName) + TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, + "[ERROR] Your strategy depends on the dataset " + dependency.name + '.') + TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, + "[ERROR] The reason that it depends on this dataset is becuase in one of your condition's Javascript Code node, you have written an expression that references this dataset. If you don't want to depend on this dataset, just locate that code and remove the mention.") + return false + } + + if (response.err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) { + throw (response.err) + } + + let dataFile = JSON.parse(response.text) + let trimmedDataFile = trimDataFile(dataFile, datasetModule.node.parentNode.record) + dataFiles.set(dependency.id, trimmedDataFile) + + function trimDataFile(dataFile, recordDefinition) { + /* + Here we will discard all the records in a file that are outside of the current time range. + We will include the las element previous to the begining of the time range. This is needed + because during the simulation, the current period is not the open one, but the previous to + the open, and if we do not include the previous to the initial datetime there will be no + current objects at the begining of the simulation for many time frames. + */ + let beginIndex + let endIndex + let result = [] + for (let i = 0; i < recordDefinition.properties.length; i++) { + let property = recordDefinition.properties[i] + if (property.config.codeName === 'begin') { + beginIndex = i + } + if (property.config.codeName === 'end') { + endIndex = i + } + } + for (let i = 0; i < dataFile.length; i++) { + let dataRecord = dataFile[i] + let begin = dataRecord[beginIndex] + let end = dataRecord[endIndex] + if (end + timeFrame < TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeRange.config.initialDatetime - 1) { continue } // /1 because we need the previous closed element + if (begin > TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeRange.config.finalDatetime) { continue } + result.push(dataRecord) + } + return result + } + } + + let mapKey = currentExchange + '-' + currentMarket + '-' + TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[n][1] + multiTimeFrameDataFiles.set(mapKey, dataFiles) } } - let mapKey = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][1]; - multiPeriodDataFiles.set(mapKey, dataFiles) + } + return true + } + + async function processDailyFiles() { + /* Telling the world we are alive and doing well and which date we are processing right now. */ + let processingDateString = tradingProcessDate.getUTCFullYear() + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(tradingProcessDate.getUTCMonth() + 1, 2) + '-' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(tradingProcessDate.getUTCDate(), 2) + TS.projects.superalgos.functionLibraries.processFunctions.processHeartBeat(processIndex, processingDateString, undefined, "Running...") + + /* + We will iterate through all the exchanges and markets involved. + */ + let exchangeList = Array.from(dataDependenciesModule.filters.exchange.list.keys()) + let marketList = Array.from(dataDependenciesModule.filters.market.list.keys()) + + for (let e = 0; e < exchangeList.length; e++) { + let currentExchange = exchangeList[e] + for (let m = 0; m < marketList.length; m++) { + let currentMarket = marketList[m] + /* + We will iterate through all posible timeFrames. + */ + for (let n = 0; n < TS.projects.superalgos.globals.timeFrames.dailyFilePeriods().length; n++) { + const timeFrameLabel = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][1] + + if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.framework.validtimeFrames !== undefined) { + let validPeriod = false + for (let i = 0; i < TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.framework.validtimeFrames.length; i++) { + let period = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.framework.validtimeFrames[i] + if (period === timeFrameLabel) { validPeriod = true } + } + if (validPeriod === false) { + continue + } + } + + if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeFrame.config.label === timeFrameLabel) { + currentTimeFrame = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][0] + currentTimeFrameLabel = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][1] + } + + dataFiles = new Map() + + /* + We will iterate through all dependencies, in order to load the + files that later will end up at the chart data structure. + */ + for (let dependencyIndex = 0; dependencyIndex < dataDependenciesModule.curatedDependencyNodeArray.length; dependencyIndex++) { + let dependency = dataDependenciesModule.curatedDependencyNodeArray[dependencyIndex] + let datasetModule = dataDependenciesModule.dataSetsModulesArray[dependencyIndex] + + if (dependency.referenceParent.config.codeName !== "Multi-Period-Daily") { + continue + } + + if (datasetModule.exchange !== currentExchange) { + continue + } + + if (datasetModule.market !== currentMarket) { + continue + } + + if (dataDependenciesModule.filters.exchange.timeFrames.get(datasetModule.exchange + '-' + datasetModule.market + '-' + datasetModule.product + '-' + timeFrameLabel) !== true) { + /* + If we can not find the current data set is used at the current time + frame we will skip this file, unless we are in the only special + case that we are retrieving candles. + */ + if (!(TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_NODE.tradingParameters.timeFrame.config.label === timeFrameLabel && datasetModule.node.parentNode.config.pluralVariableName === 'candles')) { + continue + } + if (currentExchange !== dataDependenciesModule.defaultExchange || currentMarket !== dataDependenciesModule.defaultMarket) { + continue + } + } + + /* + We will need to fetch the data of the current day and the previous day, in order for .previous properties in conditions and formulas to work well. + */ + let previousDate = new Date(tradingProcessDate.valueOf() - TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS) + let currentDate = new Date(tradingProcessDate.valueOf()) + + let previousFile = await getDataFileFromDate(previousDate) + if (previousFile === false) { return false } + let currentFile = await getDataFileFromDate(currentDate) + if (currentFile === false) { return false } + let bothFiles = previousFile.concat(currentFile) + dataFiles.set(dependency.id, bothFiles) + + async function getDataFileFromDate(processDate) { + + let dateForPath = processDate.getUTCFullYear() + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(processDate.getUTCMonth() + 1, 2) + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(processDate.getUTCDate(), 2) + let filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + timeFrameLabel + "/" + dateForPath + let fileName = "Data.json" + + /* We cut the async calls via callBacks at this point, so as to have a clearer code upstream */ + let response = await asyncGetDatasetFile(datasetModule, filePath, fileName) + + if (response.err.message === 'File does not exist.') { + TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, + "[ERROR] File not Found. This process will wait until you run your Data Mining and this file is created. File = " + filePath + '/' + fileName) + TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, + "[ERROR] Your strategy depends on the dataset " + dependency.name + '.') + TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, + "[ERROR] The reason that it depends on this dataset is becuase in one of your condition's Javascript Code node, you have written an expression that references this dataset. If you don't want to depend on this dataset, just locate that code and remove the mention.") + return false + } + if (response.err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) { + throw (response.err) + } + + return JSON.parse(response.text) + } + } + let mapKey = currentExchange + '-' + currentMarket + '-' + TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[n][1] + multiTimeFrameDataFiles.set(mapKey, dataFiles) + } + + } } return true } @@ -586,65 +671,149 @@ } } - function buildCharts(chart) { + function buildDataStructures() { + /* Fisrt Phase: Validations */ let mainDependency = {} - - /* The first phase here is about checking that we have everything we need at the definition level. */ + /* + THe first thing we do is to build an array of all the + declared dependencies of the Trading Bot. + */ let dataDependencies = TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processDependencies, 'Data Dependency') /* - We will filter ourt declared dependencies that are not present in the workspace. - This will allow the user to have less Data Mines loaded at the workspace - that the ones that a Trading Mine depends on. + Then we will filter out declared dependencies that are + not referencing nodes currently present at the workspace. + This will allow the user to have less Data Mines loaded at + the workspace that the ones that a Trading Bot depends on. */ dataDependencies = TS.projects.superalgos.utilities.nodeFunctions.filterOutNodeWihtoutReferenceParentFromNodeArray(dataDependencies) - + /* + We will run some validations to prevent starting the process + if all needed config and nodes are not present. + */ if (TS.projects.superalgos.functionLibraries.singleMarketFunctions.validateDataDependencies(processIndex, dataDependencies, callBackFunction) !== true) { return } - + /* + Next we will build an array of output datasets of this process. + We are not going to use it right now, but later down the line, + we do it just to be able to validate that all nodes and config + are ok before letting this provess run too far. + */ let outputDatasets = TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processOutput, 'Output Dataset') + /* + Here we check that all output datasets configs are ok. + */ if (TS.projects.superalgos.functionLibraries.singleMarketFunctions.validateOutputDatasets(processIndex, outputDatasets, callBackFunction) !== true) { return } - /* The second phase is about transforming the inputs into a format that can be used to apply the user defined code. */ - for (let j = 0; j < TS.projects.superalgos.globals.timeFrames.marketFilesPeriods().length; j++) { - let timeFrameLabel = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[j][1] - let dataFiles = multiPeriodDataFiles.get(timeFrameLabel) - let products = {} + /* Second Phase: Bilding the chart data structure */ - if (dataFiles !== undefined) { - TS.projects.superalgos.functionLibraries.singleMarketFunctions.inflateDatafiles(processIndex, dataFiles, dataDependencies, products, mainDependency, currentTimeFrame) + /* + This phase is about transforming the inputs into a format, + or data structure that can be used in Javascript Code and + Formula nodes to access Indicator's data. + */ - let propertyName = 'at' + timeFrameLabel.replace('-', '') - chart[propertyName] = products + let exchangeList = Array.from(dataDependenciesModule.filters.exchange.list.keys()) + let marketList = Array.from(dataDependenciesModule.filters.market.list.keys()) + + for (let e = 0; e < exchangeList.length; e++) { + let currentExchange = exchangeList[e] + for (let m = 0; m < marketList.length; m++) { + let currentMarket = marketList[m] + let splittedMarket = currentMarket.split('-') + let baseAsset = splittedMarket[0] + let quotedAsset = splittedMarket[1] + + /* Market Files */ + for (let j = 0; j < TS.projects.superalgos.globals.timeFrames.marketFilesPeriods().length; j++) { + let timeFrameLabel = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[j][1] + let dataFiles = multiTimeFrameDataFiles.get(currentExchange + '-' + currentMarket + '-' + timeFrameLabel) + let products = {} + + if (dataFiles !== undefined && dataFiles.size > 0) { + TS.projects.superalgos.functionLibraries.singleMarketFunctions.inflateDatafiles(processIndex, dataFiles, dataDependencies, products, mainDependency, currentTimeFrame) + + let propertyName = 'at' + timeFrameLabel.replace('-', '') + addProducs(propertyName, products) + } + } + + /* Daily Files */ + for (let j = 0; j < TS.projects.superalgos.globals.timeFrames.dailyFilePeriods().length; j++) { + let timeFrameLabel = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[j][1] + let dataFiles = multiTimeFrameDataFiles.get(currentExchange + '-' + currentMarket + '-' + timeFrameLabel) + let products = {} + + if (dataFiles !== undefined && dataFiles.size > 0) { + TS.projects.superalgos.functionLibraries.singleMarketFunctions.inflateDatafiles(processIndex, dataFiles, dataDependencies, products, mainDependency, currentTimeFrame) + + let propertyName = 'at' + timeFrameLabel.replace('-', '') + addProducs(propertyName, products) + } + } + + /* Single Files */ + { + let dataFiles = multiTimeFrameDataFiles.get(currentExchange + '-' + currentMarket + '-' + 'Single Files') + let products = {} + + if (dataFiles !== undefined && dataFiles.size > 0) { + TS.projects.superalgos.functionLibraries.singleMarketFunctions.inflateDatafiles(processIndex, dataFiles, dataDependencies, products, mainDependency, currentTimeFrame) + + let propertyName = 'atAnyTimeFrame' + addProducs(propertyName, products) + } + } + + function addProducs(propertyName, products) { + /* + The chart data structure allow users to simplify the syntax when they are using + the default exchange and the default market. + */ + if (currentExchange === dataDependenciesModule.defaultExchange && currentMarket === dataDependenciesModule.defaultMarket) { + chart[propertyName] = products + } + /* + The market data structure allow users to simplify the syntax when they are using + the default exchange. + */ + if (currentExchange === dataDependenciesModule.defaultExchange) { + if (market[baseAsset] === undefined) { + market[baseAsset] = {} + } + if (market[baseAsset][quotedAsset] === undefined) { + market[baseAsset][quotedAsset] = {} + } + if (market[baseAsset][quotedAsset].chart === undefined) { + market[baseAsset][quotedAsset].chart = {} + } + market[baseAsset][quotedAsset].chart[propertyName] = products + } + + if (exchange[currentExchange] === undefined) { + exchange[currentExchange] = {} + } + if (exchange[currentExchange].market === undefined) { + exchange[currentExchange].market = {} + } + if (exchange[currentExchange].market[baseAsset] === undefined) { + exchange[currentExchange].market[baseAsset] = {} + } + if (exchange[currentExchange].market[baseAsset][quotedAsset] === undefined) { + exchange[currentExchange].market[baseAsset][quotedAsset] = {} + } + if (exchange[currentExchange].market[baseAsset][quotedAsset].chart === undefined) { + exchange[currentExchange].market[baseAsset][quotedAsset].chart = {} + } + exchange[currentExchange].market[baseAsset][quotedAsset].chart[propertyName] = products + } } } - - for (let j = 0; j < TS.projects.superalgos.globals.timeFrames.dailyFilePeriods().length; j++) { - let timeFrameLabel = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[j][1] - let dataFiles = multiPeriodDataFiles.get(timeFrameLabel) - let products = {} - - if (dataFiles !== undefined) { - TS.projects.superalgos.functionLibraries.singleMarketFunctions.inflateDatafiles(processIndex, dataFiles, dataDependencies, products, mainDependency, currentTimeFrame) - - let propertyName = 'at' + timeFrameLabel.replace('-', '') - chart[propertyName] = products - } - } - - /* Single Files */ - let dataFiles = multiPeriodDataFiles.get('Single Files') - let products = {} - - if (dataFiles !== undefined) { - TS.projects.superalgos.functionLibraries.singleMarketFunctions.inflateDatafiles(processIndex, dataFiles, dataDependencies, products, mainDependency, currentTimeFrame) - - let propertyName = 'atAnyTimeFrame' - chart[propertyName] = products - } } - async function generateOutput(chart) { + async function generateOutput() { await tradingOutputModuleObject.start( chart, + market, + exchange, currentTimeFrame, currentTimeFrameLabel, tradingProcessDate @@ -676,8 +845,8 @@ outputDatasetIndex < outputDatasets.length; outputDatasetIndex++ ) { - let productCodeName = outputDatasets[outputDatasetIndex].referenceParent.parentNode.config.codeName; - await writeDataRange(productCodeName); + let productCodeName = outputDatasets[outputDatasetIndex].referenceParent.parentNode.config.codeName + await writeDataRange(productCodeName) } async function writeDataRange(productCodeName) { @@ -686,9 +855,9 @@ end: tradingProcessDate.valueOf() + TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS } - let fileContent = JSON.stringify(dataRange); - let fileName = '/Data.Range.json'; - let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + "/Output/" + TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_FOLDER_NAME + "/" + productCodeName + "/" + 'Multi-Period-Daily' + fileName; + let fileContent = JSON.stringify(dataRange) + let fileName = '/Data.Range.json' + let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + "/Output/" + TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_FOLDER_NAME + "/" + productCodeName + "/" + 'Multi-Period-Daily' + fileName let response = await fileStorage.asyncCreateTextFile(filePath, fileContent + '\n') @@ -699,7 +868,7 @@ /* Raise the event that the Data Range was Updated. */ - let key = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.config.codeName + "-" + productCodeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName + let key = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.config.codeName + "-" + productCodeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName let event = { dateRange: dataRange } @@ -715,7 +884,7 @@ outputDatasetIndex < outputDatasets.length; outputDatasetIndex++ ) { - let productCodeName = outputDatasets[outputDatasetIndex].referenceParent.parentNode.config.codeName; + let productCodeName = outputDatasets[outputDatasetIndex].referenceParent.parentNode.config.codeName await writeTimeFramesFile(currentTimeFrameLabel, productCodeName, 'Multi-Period-Daily') await writeTimeFramesFile(currentTimeFrameLabel, productCodeName, 'Multi-Period-Market') @@ -725,9 +894,9 @@ timeFramesArray.push(currentTimeFrameLabel) let fileContent = JSON.stringify(timeFramesArray) - let fileName = '/Time.Frames.json'; + let fileName = '/Time.Frames.json' - let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + "/Output/" + TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_FOLDER_NAME + "/" + productCodeName + "/" + processType + fileName; + let filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + "/Output/" + TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SESSION_FOLDER_NAME + "/" + productCodeName + "/" + processType + fileName let response = await fileStorage.asyncCreateTextFile(filePath, fileContent + '\n') if (response.err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) { @@ -749,7 +918,7 @@ async function writeMarketStatusReport(currentTimeFrameLabel) { let reportKey = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName - let thisReport = statusDependencies.statusReports.get(reportKey); + let thisReport = statusDependencies.statusReports.get(reportKey) thisReport.file.lastExecution = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).PROCESS_DATETIME thisReport.file.simulationState = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).SIMULATION_STATE @@ -777,8 +946,8 @@ if (err.stack) { TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, - "[ERROR] start -> Unhandled Exception. Will Abort this process. err = " + err.stack); - callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE); + "[ERROR] start -> Unhandled Exception. Will Abort this process. err = " + err.stack) + callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE) return } @@ -786,7 +955,7 @@ if ((err.result === "Fail Because" && err.message === "File does not exist.") || err.code === 'The specified key does not exist.') { TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] File not Found. Will Retry the Process Loop.") - callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE); + callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_RETRY_RESPONSE) return } @@ -794,8 +963,8 @@ if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) { TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, - "[ERROR] start -> Handled Exception. Will Abort this process. err = " + err.message); - callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE); + "[ERROR] start -> Handled Exception. Will Abort this process. err = " + err.message) + callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE) return } } @@ -805,7 +974,7 @@ let promise = new Promise((resolve, reject) => { - datasetModule.getTextFile(filePath, fileName, onFileReceived); + datasetModule.getTextFile(filePath, fileName, onFileReceived) function onFileReceived(err, text) { let response = { @@ -814,7 +983,7 @@ } resolve(response) } - }); + }) return promise } diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingSimulation.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingSimulation.js index 0c941284b..0bf723599 100644 --- a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingSimulation.js +++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingSimulation.js @@ -17,6 +17,8 @@ exports.newSuperalgosBotModulesTradingSimulation = function (processIndex) { async function runSimulation( chart, + market, + exchange, outputDatasetsMap, writeFiles, ) { @@ -143,10 +145,14 @@ exports.newSuperalgosBotModulesTradingSimulation = function (processIndex) { continue } - positionChartAtCurrentCandle() + positionDataStructuresAtCurrentCandle() /* The chart was recalculated based on the current candle. */ - tradingSystemModuleObject.updateChart(chart) + tradingSystemModuleObject.updateChart( + chart, + exchange, + market + ) /* Do the stuff needed previous to the run like @@ -214,7 +220,7 @@ exports.newSuperalgosBotModulesTradingSimulation = function (processIndex) { type: 'TS LF Trading Bot Info - Candle And Cycle', placeholder: {} } - + contextInfo = { candleIndex: tradingEngine.current.episode.candle.index.value, cycle: tradingEngine.current.episode.cycle.value @@ -346,73 +352,94 @@ exports.newSuperalgosBotModulesTradingSimulation = function (processIndex) { } } - function positionChartAtCurrentCandle() { + function positionDataStructuresAtCurrentCandle() { /* In conditions and Formulas, we want users to have an easy sintax to refer to indicators. In order to achieve that, we need the user to have easy access to the current candle for instance, or the current bollinger band, meaning the one the Simulation is currently standing at. For that reason we do the following processing, to have at the chart data structure the current objects of each indicator / time frame. */ - let dataDependencies = TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processDependencies, 'Data Dependency') - dataDependencies = TS.projects.superalgos.utilities.nodeFunctions.filterOutNodeWihtoutReferenceParentFromNodeArray(dataDependencies) - /* Finding the Current Element on Market Files */ - if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_PROCESSING_DAILY_FILES) { - for (let j = 0; j < TS.projects.superalgos.globals.timeFrames.dailyFilePeriods().length; j++) { - let mapKey = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[j][1] + for (const exchangeCodeName in exchange) { + let currentExchange = exchange[exchangeCodeName] + for (const baseAssetCodeName in currentExchange.market) { + let currentBaseAsset = currentExchange.market[baseAssetCodeName] + for (const quotedAssetCodeName in currentBaseAsset) { + let currentQuotedAsset = currentBaseAsset[quotedAssetCodeName] + let currentChart = currentQuotedAsset.chart + positionChart(currentChart) + } + } + } + + function positionChart(chart) { + let dataDependencies = TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processDependencies, 'Data Dependency') + dataDependencies = TS.projects.superalgos.utilities.nodeFunctions.filterOutNodeWihtoutReferenceParentFromNodeArray(dataDependencies) + + /* Finding the Current Element on Market Files */ + if (TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).TRADING_PROCESSING_DAILY_FILES) { + for (let j = 0; j < TS.projects.superalgos.globals.timeFrames.dailyFilePeriods().length; j++) { + let mapKey = TS.projects.superalgos.globals.timeFrames.dailyFilePeriods()[j][1] + let propertyName = 'at' + mapKey.replace('-', '') + let thisChart = chart[propertyName] + + if (thisChart === undefined) { continue } + + for (let k = 0; k < dataDependencies.length; k++) { + let dataDependencyNode = dataDependencies[k] + if (dataDependencyNode.referenceParent.config.codeName !== 'Multi-Period-Daily') { continue } + let singularVariableName = dataDependencyNode.referenceParent.parentNode.config.singularVariableName + let pluralVariableName = dataDependencyNode.referenceParent.parentNode.config.pluralVariableName + if (thisChart[pluralVariableName] !== undefined) { + let currentElement = getElement(thisChart[pluralVariableName], 'Daily' + '-' + mapKey + '-' + pluralVariableName) + if (currentElement !== undefined) { + thisChart[singularVariableName] = currentElement + } + } + } + } + } + + /* Finding the Current Element on Market Files */ + for (let j = 0; j < TS.projects.superalgos.globals.timeFrames.marketFilesPeriods().length; j++) { + let mapKey = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[j][1] let propertyName = 'at' + mapKey.replace('-', '') let thisChart = chart[propertyName] + if (thisChart === undefined) { continue } + for (let k = 0; k < dataDependencies.length; k++) { let dataDependencyNode = dataDependencies[k] - if (dataDependencyNode.referenceParent.config.codeName !== 'Multi-Period-Daily') { continue } + if (dataDependencyNode.referenceParent.config.codeName !== 'Multi-Period-Market') { continue } let singularVariableName = dataDependencyNode.referenceParent.parentNode.config.singularVariableName let pluralVariableName = dataDependencyNode.referenceParent.parentNode.config.pluralVariableName if (thisChart[pluralVariableName] !== undefined) { - let currentElement = getElement(thisChart[pluralVariableName], 'Daily' + '-' + mapKey + '-' + pluralVariableName) + let currentElement = getElement(thisChart[pluralVariableName], 'Market' + '-' + mapKey + '-' + pluralVariableName) if (currentElement !== undefined) { thisChart[singularVariableName] = currentElement } } } } - } - /* Finding the Current Element on Market Files */ - for (let j = 0; j < TS.projects.superalgos.globals.timeFrames.marketFilesPeriods().length; j++) { - let mapKey = TS.projects.superalgos.globals.timeFrames.marketFilesPeriods()[j][1] - let propertyName = 'at' + mapKey.replace('-', '') + /* Finding the Current Element At Single Files*/ + let propertyName = 'atAnyTimeFrame' let thisChart = chart[propertyName] + if (thisChart === undefined) { return } + for (let k = 0; k < dataDependencies.length; k++) { let dataDependencyNode = dataDependencies[k] - if (dataDependencyNode.referenceParent.config.codeName !== 'Multi-Period-Market') { continue } + if (dataDependencyNode.referenceParent.config.codeName !== 'Single-File') { continue } let singularVariableName = dataDependencyNode.referenceParent.parentNode.config.singularVariableName let pluralVariableName = dataDependencyNode.referenceParent.parentNode.config.pluralVariableName - if (thisChart[pluralVariableName] !== undefined) { - let currentElement = getElement(thisChart[pluralVariableName], 'Market' + '-' + mapKey + '-' + pluralVariableName) - if (currentElement !== undefined) { - thisChart[singularVariableName] = currentElement - } + let elementArray = thisChart[pluralVariableName] + let currentElement + if (elementArray !== undefined) { + currentElement = elementArray[elementArray.length - 1] } + thisChart[singularVariableName] = currentElement } } - - /* Finding the Current Element At Single Files*/ - let propertyName = 'atAnyTimeFrame' - let thisChart = chart[propertyName] - - for (let k = 0; k < dataDependencies.length; k++) { - let dataDependencyNode = dataDependencies[k] - if (dataDependencyNode.referenceParent.config.codeName !== 'Single-File') { continue } - let singularVariableName = dataDependencyNode.referenceParent.parentNode.config.singularVariableName - let pluralVariableName = dataDependencyNode.referenceParent.parentNode.config.pluralVariableName - let elementArray = thisChart[pluralVariableName] - let currentElement - if (elementArray !== undefined) { - currentElement = elementArray[elementArray.length - 1] - } - thisChart[singularVariableName] = currentElement - } } function getElement(pArray, datasetName) { diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingStages.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingStages.js index 7dbdd2c5e..ef55ba96c 100644 --- a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingStages.js +++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingStages.js @@ -71,8 +71,8 @@ exports.newSuperalgosBotModulesTradingStages = function (processIndex) { tradingEpisodeModuleObject = undefined } - function updateChart(pChart) { - snapshotsModuleObject.updateChart(pChart) + function updateChart(pChart, pExchange, pMarket) { + snapshotsModuleObject.updateChart(pChart, pExchange, pMarket) } function mantain() { diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingSystem.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingSystem.js index fbc9c9dea..e784c7e28 100644 --- a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingSystem.js +++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/TradingSystem.js @@ -13,7 +13,14 @@ exports.newSuperalgosBotModulesTradingSystem = function (processIndex) { finalize: finalize } + /* + These 3 are the main data structures available to users + when writing conditions and formulas. + */ let chart + let exchange + let market + let tradingSystem let tradingEngine let sessionParameters @@ -115,6 +122,8 @@ exports.newSuperalgosBotModulesTradingSystem = function (processIndex) { tradingStagesModuleObject = undefined chart = undefined + exchange = undefined + market = undefined tradingSystem.conditions = undefined tradingSystem.formulas = undefined @@ -151,9 +160,16 @@ exports.newSuperalgosBotModulesTradingSystem = function (processIndex) { tradingSystem.announcements = [] } - function updateChart(pChart) { - chart = pChart // We need chat to be a local object accessible from conditions and formulas. - tradingStagesModuleObject.updateChart(pChart) + function updateChart(pChart, pExchange, pMarket) { + /* + We need these 3 data structures to be a local objects + accessible while evaluating conditions and formulas. + */ + chart = pChart + exchange = pExchange + market = pMarket + + tradingStagesModuleObject.updateChart(pChart, pExchange, pMarket) } function buildDynamicIndicators() { diff --git a/Projects/Superalgos/TS/Function-Libraries/SessionFunctions.js b/Projects/Superalgos/TS/Function-Libraries/SessionFunctions.js index 4cfc063ee..c1c6818a1 100644 --- a/Projects/Superalgos/TS/Function-Libraries/SessionFunctions.js +++ b/Projects/Superalgos/TS/Function-Libraries/SessionFunctions.js @@ -1,5 +1,7 @@ exports.newSuperalgosFunctionLibrariesSessionFunctions = function () { + const MODULE_NAME = "Session Functions" + let thisObject = { sessionHeartBeat: sessionHeartBeat, stopSession: stopSession, diff --git a/Projects/Superalgos/TS/Function-Libraries/SingleMarketFunctions.js b/Projects/Superalgos/TS/Function-Libraries/SingleMarketFunctions.js index 0246e4b63..3534e24eb 100644 --- a/Projects/Superalgos/TS/Function-Libraries/SingleMarketFunctions.js +++ b/Projects/Superalgos/TS/Function-Libraries/SingleMarketFunctions.js @@ -520,7 +520,7 @@ dateForPath = "/" + currentDay.getUTCFullYear() + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(currentDay.getUTCMonth() + 1, 2) + '/' + TS.projects.superalgos.utilities.miscellaneousFunctions.pad(currentDay.getUTCDate(), 2); } - let filePathRoot = 'Project/' + contextSummary.project + "/" + contextSummary.mineType + "/" + contextSummary.dataMine + "/" + contextSummary.bot + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName + let filePathRoot = 'Project/' + contextSummary.project + "/" + contextSummary.mineType + "/" + contextSummary.dataMine + "/" + contextSummary.bot + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName let filePath = filePathRoot + "/Output/" + contextSummary.product + "/" + contextSummary.dataset + "/" + timeFrameLabel + dateForPath; filePath += '/' + fileName @@ -649,7 +649,7 @@ "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.config.codeName + '/' + - TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" + diff --git a/Projects/Superalgos/TS/Process-Modules/DataDependencies.js b/Projects/Superalgos/TS/Process-Modules/DataDependencies.js index 1c7789468..147fac5d3 100644 --- a/Projects/Superalgos/TS/Process-Modules/DataDependencies.js +++ b/Projects/Superalgos/TS/Process-Modules/DataDependencies.js @@ -1,18 +1,47 @@ exports.newSuperalgosProcessModulesDataDependencies = function (processIndex) { + /* + This module mantains a curated array of Data Dependency nodes, + which is not exactly the ones listed at the Process Dependencies, + but a smaller subset based on the circunstances found at the user's + workspace. For example: + + 1. Dependencies without a Reference Parent are filtered out. + 2. Dependencies which don't have a Data Set are filtered out. - const MODULE_NAME = "Data Dependencies"; + It also mantains an array of Data Set Modules, which are the + one's that ultimately know how to load a file based on the + network configuration found at the workspace at the moment this + Task was launched. + + Finally it mantains a Filter map, that allows the users of this module + to filter out data dependencies based on the code written by users + at the Javascript Code and Formula nodes. + */ + const MODULE_NAME = "Data Dependencies" let thisObject = { - nodeArray: undefined, + filters: undefined, + defaultExchange: undefined, + defaultMarket: undefined, + curatedDependencyNodeArray: undefined, dataSetsModulesArray: [], - isItADepenency: isItADepenency, initialize: initialize, finalize: finalize - }; + } - let filter = new Map() + thisObject.filters = { + market: { + list: new Map() + }, + exchange: { + list: new Map(), + markets: new Map(), + products: new Map(), + timeFrames: new Map() + } + } - return thisObject; + return thisObject function initialize(callBackFunction) { try { @@ -21,50 +50,80 @@ /* First we will get all the data dependencies of the bot, as defined at the Trading Mine. */ - thisObject.nodeArray = TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processDependencies, 'Data Dependency') - if (thisObject.nodeArray.length === 0) { - TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] initialize -> onInitilized -> It is not possible to not have data dependencies at all."); + thisObject.curatedDependencyNodeArray = TS.projects.superalgos.utilities.nodeFunctions.nodeBranchToArray(TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processDependencies, 'Data Dependency') + if (thisObject.curatedDependencyNodeArray.length === 0) { + TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] initialize -> onInitilized -> It is not possible to not have data dependencies at all.") callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE) return } /* - We will filter ourt declared dependencies that are not present in the workspace. + We will filter out declared dependencies that are not present in the workspace. This will allow the user to have less Data Mines loaded at the workspace that the ones that a Trading Mine depends on. */ - thisObject.nodeArray = TS.projects.superalgos.utilities.nodeFunctions.filterOutNodeWihtoutReferenceParentFromNodeArray(thisObject.nodeArray) + thisObject.curatedDependencyNodeArray = TS.projects.superalgos.utilities.nodeFunctions.filterOutNodeWihtoutReferenceParentFromNodeArray(thisObject.curatedDependencyNodeArray) } else { - TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] initialize -> onInitilized -> It is not possible not to have process dependencies, which means not data dependencies."); + TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] initialize -> onInitilized -> It is not possible not to have process dependencies, which means not data dependencies.") callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE) return } - if (thisObject.nodeArray.length === 0) { + if (thisObject.curatedDependencyNodeArray.length === 0) { // We allow old indicators not to declare their data dependencies. - - callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE); - return; - } - - /* Session based dependency filters */ - if (TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).DEPENDENCY_FILTER !== undefined) { - for (let i = 0; i < TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).DEPENDENCY_FILTER.length; i++) { - let key = TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).DEPENDENCY_FILTER[i] - filter.set(key, true) - } + callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE) + return } /* - For each dependency declared at the nodeArray, we will initialize a DataSet as part of this initialization process. + Store here the default exchange and market. */ + thisObject.defaultExchange = TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName + thisObject.defaultMarket = + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + + "-" + + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName + + /* Session based dependency thisObject.filters */ + let receivedDependencyFilters = TS.projects.superalgos.globals.processConstants.CONSTANTS_BY_PROCESS_INDEX_MAP.get(processIndex).DEPENDENCY_FILTER + if (receivedDependencyFilters !== undefined) { + + /* + Javascript Maps can not travel stringified at ta JSON object, so we receive + these maps in an Array format, and here we will just convert them to Maps, + that is how we need them. + */ + arrayToMap(receivedDependencyFilters.market.list, thisObject.filters.market.list) + + arrayToMap(receivedDependencyFilters.exchange.list, thisObject.filters.exchange.list) + arrayToMap(receivedDependencyFilters.exchange.markets, thisObject.filters.exchange.markets) + arrayToMap(receivedDependencyFilters.exchange.products, thisObject.filters.exchange.products) + arrayToMap(receivedDependencyFilters.exchange.timeFrames, thisObject.filters.exchange.timeFrames) + + function arrayToMap(array, map) { + for (let i = 0; i < array.length; i++) { + let key = array[i] + map.set(key, true) + } + } + } else { + /* + If we did not receive any filters, like in the case of Indicators and Sensors, + we need to add the default exchange and market to these maps in order + for the following sections to work. + */ + thisObject.filters.exchange.list.set(thisObject.defaultExchange, true) + thisObject.filters.exchange.markets.set(thisObject.defaultExchange + '-' + thisObject.defautMarket, true) + } + /* + For each dependency declared at the curatedDependencyNodeArray, we will initialize a + DataSet as part of this initialization process. + */ let alreadyCalledBack = false - let addCount = 0 - let skipCount = 0 /* - The current nodeArray that we have includes all the dependencies daclared in the Data Mine | Trading Mine | Learning Mine + The current curatedDependencyNodeArray that we have includes all the dependencies daclared in the Data Mine | Trading Mine | Learning Mine process dependencies, minus the ones without reference parent, meaning that references Data Mines that are not present at the workspace. From all the remaining dependencies there will be others that we need to filter out, and they are the ones which the user does not have a data product anywhere on the network where @@ -72,44 +131,97 @@ out is by analizyng the response of the initialization call to the DataSet module. If it did not fail but it was not initialized, then we will assume this happened because the data could not be located and we will assume the user did this on purpose and we will filter out this dependency by not putting it on this new array. - */ + */ let newNodeArray = [] - for (let i = 0; i < thisObject.nodeArray.length; i++) { - let dataSetModule = TS.projects.superalgos.processModules.dataset.newSuperalgosProcessModulesDataset(processIndex); - dataSetModule.initialize(thisObject.nodeArray[i], onInitilized); + let exchangeList = Array.from(thisObject.filters.exchange.list.keys()) + let marketList = Array.from(thisObject.filters.market.list.keys()) - function onInitilized(err, wasInitialized) { - - if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) { - TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] initialize -> onInitilized -> err = " + JSON.stringify(err)); - - alreadyCalledBack = true; - callBackFunction(err); - return; - } - - if (wasInitialized === true) { - addCount++; - newNodeArray.push(thisObject.nodeArray[i]) - addDataSet() + /* + For each Exchange / Market we will add the datasets objects to our collection. + */ + for (let e = 0; e < exchangeList.length; e++) { + let exchange = exchangeList[e] + for (let m = 0; m < marketList.length; m++) { + let market = marketList[m] + if (receivedDependencyFilters !== undefined) { + /* + If we received a Dependency Filter from the UI, we will apply it here so + as not to add DataSets that we wont actually need. + */ + if (thisObject.filters.exchange.markets.get(exchange + '-' + market) === true) { + addDataSets(exchange, market) + } } else { - skipCount++ + /* + If we did not received these dependency filters, like when we are processing + Indicators, we will just add all datasets from exchange / market combination + because it will only be one combination: the default exchange and the default market. + */ + addDataSets(exchange, market) } - checkIfWeAreDone() } + } - function addDataSet() { - thisObject.dataSetsModulesArray.push(dataSetModule); - } + if (alreadyCalledBack === false) { + alreadyCalledBack = true + thisObject.curatedDependencyNodeArray = newNodeArray + callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE) + return + } - function checkIfWeAreDone() { - if (addCount + skipCount === thisObject.nodeArray.length) { - if (alreadyCalledBack === false) { - alreadyCalledBack = true - thisObject.nodeArray = newNodeArray - callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE); - return; + function addDataSets(exchange, market) { + for (let i = 0; i < thisObject.curatedDependencyNodeArray.length; i++) { + + let dataDependency = thisObject.curatedDependencyNodeArray[i] + + if (receivedDependencyFilters !== undefined) { + /* + If we received a Dependency Filter from the UI, we will make these excta checks + before instantiating a Data Set Module. + */ + if (dataDependency.referenceParent === undefined) { + continue + } + if (dataDependency.referenceParent.parentNode === undefined) { + continue + } + if (dataDependency.referenceParent.parentNode.config.singularVariableName === undefined) { + continue + } + /* + This is the product related to this Data Dependency, as the user would type it + at a Condition or Formula and appear at the UI provided filter. + */ + let product = dataDependency.referenceParent.parentNode.config.singularVariableName + + if (thisObject.filters.exchange.products.get(exchange + '-' + market + '-' + product) !== true) { + continue + } + addDataSet(exchange, market) + } else { + addDataSet(exchange, market) + } + + function addDataSet(exchange, market) { + + let dataSetModule = TS.projects.superalgos.processModules.dataset.newSuperalgosProcessModulesDataset(processIndex) + dataSetModule.initialize(exchange, market, dataDependency, onInitilized) + + function onInitilized(err, wasInitialized) { + + if (err.result !== TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE.result) { + TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] initialize -> onInitilized -> err = " + JSON.stringify(err)) + + alreadyCalledBack = true + callBackFunction(err) + return + } + + if (wasInitialized === true) { + newNodeArray.push(thisObject.curatedDependencyNodeArray[i]) + thisObject.dataSetsModulesArray.push(dataSetModule) + } } } } @@ -117,8 +229,8 @@ } catch (err) { TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err - TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack); - callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE); + TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack) + callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE) } } @@ -128,13 +240,10 @@ dataSetModule.finalize() } thisObject.dataSetsModulesArray = undefined - filter = undefined + thisObject.curatedDependencyNodeArray = undefined + thisObject.filters = undefined + thisObject.defaultExchange = undefined + thisObject.defaultMarket = undefined bot = undefined } - - function isItADepenency(timeFrame, product) { - let key = timeFrame + '-' + product - - return filter.get(key) - } -}; +} diff --git a/Projects/Superalgos/TS/Process-Modules/Dataset.js b/Projects/Superalgos/TS/Process-Modules/Dataset.js index 69175b4d4..45a40ffb2 100644 --- a/Projects/Superalgos/TS/Process-Modules/Dataset.js +++ b/Projects/Superalgos/TS/Process-Modules/Dataset.js @@ -1,10 +1,17 @@ exports.newSuperalgosProcessModulesDataset = function (processIndex) { - + /* + This module represents a Dataset at a certain localtion on the + network, and it is able to load a file from that dataset or + write one into it. + */ const MODULE_NAME = "Dataset"; let thisObject = { node: undefined, networkNode: undefined, + exchange: undefined, + market: undefined, + product: undefined, initialize: initialize, finalize: finalize, getTextFile: getTextFile, @@ -12,16 +19,16 @@ exports.newSuperalgosProcessModulesDataset = function (processIndex) { }; /* Storage account to be used here. */ - - let fileStorage return thisObject; - function initialize(dataDependency, callBackFunction) { + function initialize(exchange, market, dataDependency, callBackFunction) { try { thisObject.node = dataDependency.referenceParent; + thisObject.exchange = exchange + thisObject.market = market /* Some very basic validations that we have all the information needed. */ if (thisObject.node === undefined) { @@ -74,15 +81,19 @@ exports.newSuperalgosProcessModulesDataset = function (processIndex) { /* Now we will see where do we need to fetch this data from. */ let network = TS.projects.superalgos.globals.taskConstants.NETWORK_NODE - let datasetProductDefinition = thisObject.node.parentNode + let productDefinition = thisObject.node.parentNode + thisObject.product = productDefinition.config.singularVariableName - let nodeArray = TS.projects.superalgos.utilities.nodeFunctions.nodeMeshToPathArray(network, datasetProductDefinition.id) - let networkNode = TS.projects.superalgos.utilities.nodeFunctions.findNodeInNodeArray(nodeArray, 'Network Node') + /* + We will find the networkNode that leads to this Product Definition + and is related to this exchange and market. + */ + let networkNode = fincNetworkNode(network, productDefinition, thisObject.exchange, thisObject.market) if (networkNode === undefined) { TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[WARN] initialize -> Network Node not found.") TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[WARN] initialize -> Initialization Failed because we could not find where the data of this dataset is located within the network. Check the logs for more info."); - TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[WARN] initialize -> Could not find where " + datasetProductDefinition.name + " for " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + " " + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName + " is stored within the network."); + TS.projects.superalgos.globals.loggerVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).BOT_MAIN_LOOP_LOGGER_MODULE_OBJECT.write(MODULE_NAME, "[WARN] initialize -> Could not find where " + productDefinition.name + " for " + thisObject.exchange + " " + thisObject.market + " is stored within the network."); callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_OK_RESPONSE, false); return } @@ -103,6 +114,8 @@ exports.newSuperalgosProcessModulesDataset = function (processIndex) { function finalize() { fileStorage = undefined thisObject.networkNode = undefined + thisObject.exchange = undefined + thisObject.market = undefined bot = undefined thisObject = undefined } @@ -115,7 +128,7 @@ exports.newSuperalgosProcessModulesDataset = function (processIndex) { let project = thisObject.node.parentNode.parentNode.parentNode.project let botCodeName = thisObject.node.parentNode.parentNode.config.codeName - let filePathRoot = 'Project/' + project + "/" + mineType + "/" + mine + "/" + botCodeName + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName + let filePathRoot = 'Project/' + project + "/" + mineType + "/" + mine + "/" + botCodeName + '/' + thisObject.exchange + "/" + thisObject.market let filePath = filePathRoot + "/Output/" + pFolderPath; filePath += '/' + pFileName @@ -153,7 +166,7 @@ exports.newSuperalgosProcessModulesDataset = function (processIndex) { return; } - let filePathRoot = 'Project/' + thisObject.node.project + "/" + thisObject.node.mineType + "/" + thisObject.node.dataMine + "/" + thisObject.node.bot + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName + let filePathRoot = 'Project/' + thisObject.node.project + "/" + thisObject.node.mineType + "/" + thisObject.node.dataMine + "/" + thisObject.node.bot + '/' + thisObject.exchange + "/" + thisObject.market let filePath = filePathRoot + "/Output/" + pFolderPath + '/' + pFileName; fileStorage.createTextFile(filePath, pFileContent, onFileCreated); @@ -168,4 +181,148 @@ exports.newSuperalgosProcessModulesDataset = function (processIndex) { callBackFunction(TS.projects.superalgos.globals.standardResponses.DEFAULT_FAIL_RESPONSE); } } + + function fincNetworkNode(network, productDefinition, exchange, market) { + /* + + The problem that we need to solve here is the following: + + A. We are interested in a particular Exchange and Market. + B. We have the Network we received from the UI whe the user ran the Task. + C. We have the Product Definition that is the parent node of the Data Set represented by this object. + D. This Product Definition is referenced by one or more Data Products nodes at some branch of the Network Hirierchy. + E. We need to find the right Data Product node, the one who is itself a descendent of the Market Data Products + node that is referencing the market and exchange that we have as a parameter of this function. + + So, the strategy we will implement is the following: + + 1. We will scan all the branches of the Network received from the UI. + 2. Once we find a Market Data Products, Market Trading Products o Market Learning Products we will check + that they are referencing the market and exchange we need, other wise we ignore them and continue + with the scanning. + 3. Once found, we will go into their own branches and find a path until the Product Definition we need to reach. + 4. Once reached, we will know which Network Node is on the full path from the Network to the Product Definition and + we solved the problem. + + */ + let found = false + let networkNode + let splittedMarket = market.split('-') + let baseAsset = splittedMarket[0] + let quotedAsset = splittedMarket[1] + + scanNodeMesh(network) + + if (found === true) { + return networkNode + } else { + return + } + + function scanNodeMesh(startingNode) { + if (startingNode === undefined) { return } + + let schemaDocument = TS.projects.superalgos.globals.taskConstants.APP_SCHEMA_MAP.get(startingNode.project + '-' + startingNode.type) + if (schemaDocument === undefined) { return } + + if (startingNode.id === productDefinition.id) { + /* + We reached the point that we found a path to the Product Definition. + Now we know that the last netwrokNode is the node that has the correct + path. + */ + found = true + return + } + + if (startingNode.type === 'Network Node') { + /* + We will store the Network Node here so that if we find the rignt path + we can know from which Netwrok Node it going through. + */ + networkNode = startingNode + } + + if ( + startingNode.type === 'Market Data Products' || + startingNode.type === 'Market Trading Products' || + startingNode.type === 'Market Learning Products' + ) { + /* + We will check that this guy is referencing the right market and the + market is a descendant of the right exchange. Otherwise we wont process + their children. + */ + if (startingNode.referenceParent === undefined) { + return + } + if (startingNode.referenceParent.baseAsset === undefined) { + return + } + if (startingNode.referenceParent.quotedAsset === undefined) { + return + } + if (startingNode.referenceParent.baseAsset.referenceParent === undefined) { + return + } + if (startingNode.referenceParent.quotedAsset.referenceParent === undefined) { + return + } + if (startingNode.referenceParent.baseAsset.referenceParent.config.codeName !== baseAsset) { + return + } + if (startingNode.referenceParent.quotedAsset.referenceParent.config.codeName !== quotedAsset) { + return + } + if (startingNode.referenceParent.parentNode === undefined) { + return + } + if (startingNode.referenceParent.parentNode.parentNode === undefined) { + return + } + if (startingNode.referenceParent.parentNode.parentNode.config.codeName !== exchange) { + return + } + } + + /* We scan through this node children */ + if (schemaDocument.childrenNodesProperties !== undefined) { + for (let i = 0; i < schemaDocument.childrenNodesProperties.length; i++) { + let property = schemaDocument.childrenNodesProperties[i] + + switch (property.type) { + case 'node': { + if (found !== true) { + scanNodeMesh(startingNode[property.name]) + } + } + break + case 'array': { + let startingNodePropertyArray = startingNode[property.name] + if (startingNodePropertyArray !== undefined) { + for (let m = 0; m < startingNodePropertyArray.length; m++) { + if (found !== true) { + scanNodeMesh(startingNodePropertyArray[m]) + } + } + } + break + } + } + } + } + /* We scan parents nodes. */ + if (startingNode.parentNode !== undefined) { + if (found !== true) { + scanNodeMesh(startingNode.parentNode) + } + } + /* We scan reference parents too. */ + if (startingNode.referenceParent !== undefined) { + if (found !== true) { + scanNodeMesh(startingNode.referenceParent) + } + } + } + } }; diff --git a/Projects/Superalgos/TS/Process-Modules/ProcessExecutionEvents.js b/Projects/Superalgos/TS/Process-Modules/ProcessExecutionEvents.js index 0b4ce70c2..2a0912ca4 100644 --- a/Projects/Superalgos/TS/Process-Modules/ProcessExecutionEvents.js +++ b/Projects/Superalgos/TS/Process-Modules/ProcessExecutionEvents.js @@ -33,7 +33,7 @@ } let market = TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName - currentProcessKey = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.name + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.type + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.id + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "-" + market + currentProcessKey = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.name + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.type + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.id + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName + "-" + market /* A process can depend for its own execution on another process to finish, and @@ -191,7 +191,7 @@ let extraCallerId = '-' + Math.trunc(Math.random() * 10000) + '-' let market = TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName - let key = processThisDependsOn.name + "-" + processThisDependsOn.type + "-" + processThisDependsOn.id + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "-" + market + let key = processThisDependsOn.name + "-" + processThisDependsOn.type + "-" + processThisDependsOn.id + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName + "-" + market let callerId = TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.config.codeName + extraCallerId let subscriptionId diff --git a/Projects/Superalgos/TS/Process-Modules/ProcessOutput.js b/Projects/Superalgos/TS/Process-Modules/ProcessOutput.js index dfcc1dbec..938cb5900 100644 --- a/Projects/Superalgos/TS/Process-Modules/ProcessOutput.js +++ b/Projects/Superalgos/TS/Process-Modules/ProcessOutput.js @@ -87,7 +87,7 @@ let product = outputDataset.referenceParent.parentNode.config.codeName let dataset = outputDataset.referenceParent.config.codeName - let key = dataMine + "-" + botName + "-" + product + "-" + dataset + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName + let key = dataMine + "-" + botName + "-" + product + "-" + dataset + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName let event = { lastFile: lastFile, timeFrames: timeFrames @@ -170,7 +170,7 @@ let product = outputDataset.referenceParent.parentNode.config.codeName let dataset = outputDataset.referenceParent.config.codeName - let key = dataMine + "-" + botName + "-" + product + "-" + dataset + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName + let key = dataMine + "-" + botName + "-" + product + "-" + dataset + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName let event = { lastFile: lastFile, timeFrames: timeFrames diff --git a/Projects/Superalgos/TS/Process-Modules/StatusReport.js b/Projects/Superalgos/TS/Process-Modules/StatusReport.js index 3fe00aa99..f7ac102b2 100644 --- a/Projects/Superalgos/TS/Process-Modules/StatusReport.js +++ b/Projects/Superalgos/TS/Process-Modules/StatusReport.js @@ -252,7 +252,7 @@ if (ownerId !== botId) { - let filePathRoot = 'Project/' + statusDependencyNode.project + "/" + statusDependencyNode.mineType + "/" + statusDependencyNode.dataMine + "/" + statusDependencyNode.bot + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName + let filePathRoot = 'Project/' + statusDependencyNode.project + "/" + statusDependencyNode.mineType + "/" + statusDependencyNode.dataMine + "/" + statusDependencyNode.bot + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName + "/" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + "-" + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName filePath = filePathRoot + "/Reports/" + sessionPath + statusDependencyNode.process } else { filePath = TS.projects.superalgos.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).FILE_PATH_ROOT + "/Reports/" + sessionPath + statusDependencyNode.process diff --git a/Projects/Superalgos/TS/Utilities/DateTimeFunctions.js b/Projects/Superalgos/TS/Utilities/DateTimeFunctions.js index 60e1cd53b..0dacf20b3 100644 --- a/Projects/Superalgos/TS/Utilities/DateTimeFunctions.js +++ b/Projects/Superalgos/TS/Utilities/DateTimeFunctions.js @@ -8,7 +8,7 @@ exports.newSuperalgosUtilitiesDateTimeFunctions = function () { return thisObject - function removeTime (datetime) { + function removeTime(datetime) { let date = new Date(datetime) return new Date(date.getUTCFullYear() + "-" + (date.getUTCMonth() + 1) + "-" + date.getUTCDate() + " " + "00:00" + TS.projects.superalgos.globals.timeConstants.GMT_SECONDS); } @@ -16,11 +16,12 @@ exports.newSuperalgosUtilitiesDateTimeFunctions = function () { function getPercentage(fromDate, currentDate, lastDate) { let fromDays = Math.trunc(fromDate.valueOf() / TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS) let currentDays = Math.trunc(currentDate.valueOf() / TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS) - let lastDays = Math.trunc(lastDate.valueOf() / TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS) + let lastDays = Math.trunc((lastDate.valueOf() - TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS) / TS.projects.superalgos.globals.timeConstants.ONE_DAY_IN_MILISECONDS) let percentage = (currentDays - fromDays) * 100 / (lastDays - fromDays) if ((lastDays - fromDays) === 0) { percentage = 100 } + if (percentage > 100) { percentage = 100 } return percentage } diff --git a/Projects/Superalgos/TS/Utilities/NodeFunctions.js b/Projects/Superalgos/TS/Utilities/NodeFunctions.js index 13a95bdfc..7ca293528 100644 --- a/Projects/Superalgos/TS/Utilities/NodeFunctions.js +++ b/Projects/Superalgos/TS/Utilities/NodeFunctions.js @@ -103,7 +103,7 @@ exports.newSuperalgosUtilitiesNodeFunctions = function () { function nodeMeshToPathArray (node, nodeId) { /* - This function scans a node mesh for a certain node if and + This function scans a node mesh for a certain node id and returns an array with the path within that mesh to the requested node. */ diff --git a/Projects/Superalgos/UI/Function-Libraries/DependenciesFilter.js b/Projects/Superalgos/UI/Function-Libraries/DependenciesFilter.js index d91490ba0..295b8baf8 100644 --- a/Projects/Superalgos/UI/Function-Libraries/DependenciesFilter.js +++ b/Projects/Superalgos/UI/Function-Libraries/DependenciesFilter.js @@ -1,29 +1,51 @@ function newSuperalgosFunctionLibraryDependenciesFilter() { /* + A Dependency Filter is list of Indicators a Strategy depends + on, that is later used to filter out all the other indicators + the Trading Bot depends on. + The function will scen a node branch, most likely a Trading System, looking into the code property of each node. It will analyze it's content and try to make a list of all indicators mentioned at the code text and at which time frames they are mentioned. - It is important to note that all node that are not of the type - Javascript Code are going to be filtered out. + It is important to note that all nodes that are not of the type + Javascript Code or Formula are going to be ignored. */ thisObject = { - createFilter: createFilter + createDependencyFilter: createDependencyFilter } return thisObject - function createFilter(node) { - let filters = new Map() - recursiveFilter(node) + function createDependencyFilter(defaultExchange, defaultMarket, tradingSystem) { + let filters = { + market: { + list: new Map() + }, + exchange: { + list: new Map(), + markets: new Map(), + products: new Map(), + timeFrames: new Map() + } + } + recursiveFilter(tradingSystem) - return Array.from(filters.keys()) + /* Transform the Map into arrays */ + filters.market.list = Array.from(filters.market.list.keys()) + + filters.exchange.list = Array.from(filters.exchange.list.keys()) + filters.exchange.markets = Array.from(filters.exchange.markets.keys()) + filters.exchange.products = Array.from(filters.exchange.products.keys()) + filters.exchange.timeFrames = Array.from(filters.exchange.timeFrames.keys()) + + return filters function recursiveFilter(node) { - if (node.type === 'Javascript Code' || node.type === 'Formula' ) { + if (node.type === 'Javascript Code' || node.type === 'Formula') { filter(node.code) - } + } let schemaDocument = getSchemaDocument(node) if (schemaDocument !== undefined) { @@ -60,24 +82,96 @@ function newSuperalgosFunctionLibraryDependenciesFilter() { function filter(code) { if (code === undefined) { return } - + /* + We will clean the code from symbols that we do not need during our dependency analysis. + */ + code = code.replaceAll(',', '') + code = code.replaceAll('(', '') + code = code.replaceAll(')', '') + code = code.replaceAll('{', '') + code = code.replaceAll('}', '') + code = code.replaceAll('!', '') + code = code.replaceAll('|', '') + code = code.replaceAll('<', '') + code = code.replaceAll('>', '') + code = code.replaceAll('=', '') + code = code.replaceAll('\n', ' ') + /* + We will analyze each instruction of the code. + */ let instructionsArray = code.split(' ') for (let i = 0; i < instructionsArray.length; i++) { let instruction = instructionsArray[i] - if (instruction.indexOf('chart') >= 0) { + /* + The first kind of instruction we will handle are the ones + related to the chart structure. For that we need the + instruction to start with the keyword 'chart'. + */ + if (instruction.indexOf('chart') === 0) { // Example: chart.at01hs.popularSMA.sma200 - chart.at01hs.popularSMA.sma100 < 10 let parts = instruction.split('.') let timeFrame = parts[1] let product = parts[2] - let productParts = product.split(',') - product = productParts[0] - productParts = product.split(')') - product = productParts[0] - - // Example: chart.at01hs.popularSMA.sma200 - chart.at01hs.popularSMA.sma100 < 10 + /* + From the instruction syntax we will get the timeFrame + */ if (timeFrame !== 'atAnyTimeFrame') { timeFrame = timeFrame.substring(2, 4) + '-' + timeFrame.substring(4, 7) } - filters.set(timeFrame + '-' + product, true) + filters.market.list.set(defaultMarket, true) + + filters.exchange.timeFrames.set(defaultExchange + '-' + defaultMarket + '-' + product + '-' + timeFrame, true) + filters.exchange.products.set(defaultExchange + '-' + defaultMarket + '-' + product, true) + filters.exchange.markets.set(defaultExchange + '-' + defaultMarket, true) + filters.exchange.list.set(defaultExchange, true) + } + /* + The second kind of instruction we will handle are the ones + related to the market data structure. For that we need + the instruction to start with the keyword 'market' + */ + if (instruction.indexOf('market') === 0) { // Example: market.BTC.USDT.chart.at01hs.popularSMA.sma200 - market.ETC.USDT.chart.at01hs.popularSMA.sma100 < 10 + let parts = instruction.split('.') + let baseAsset = parts[1] + let quotedAsset = parts[2] + let timeFrame = parts[4] + let product = parts[5] + /* + From the instruction syntax we will get the timeFrame + */ + if (timeFrame !== 'atAnyTimeFrame') { + timeFrame = timeFrame.substring(2, 4) + '-' + timeFrame.substring(4, 7) + } + filters.market.list.set(baseAsset + '-' + quotedAsset, true) + + filters.exchange.timeFrames.set(defaultExchange + '-' + baseAsset + '-' + quotedAsset + '-' + product + '-' + timeFrame, true) + filters.exchange.products.set(defaultExchange + '-' + baseAsset + '-' + quotedAsset + '-' + product, true) + filters.exchange.markets.set(defaultExchange + '-' + baseAsset + '-' + quotedAsset, true) + filters.exchange.list.set(defaultExchange, true) + } + /* + The third kind of instruction we will handle are the ones + related to the exchange data structure. For that we need + the instruction to start with the keyword 'market' + */ + if (instruction.indexOf('exchange') === 0) { // Example: exchange.binance.market.BTC.USDT.chart.at01hs.popularSMA.sma200 - exchange.poloniex.market.ETC.USDT.chart.at01hs.popularSMA.sma100 < 10 + let parts = instruction.split('.') + let exchange = parts[1] + let baseAsset = parts[3] + let quotedAsset = parts[4] + let timeFrame = parts[6] + let product = parts[7] + /* + From the instruction syntax we will get the timeFrame + */ + if (timeFrame !== 'atAnyTimeFrame') { + timeFrame = timeFrame.substring(2, 4) + '-' + timeFrame.substring(4, 7) + } + filters.market.list.set(baseAsset + '-' + quotedAsset, true) + + filters.exchange.timeFrames.set(exchange + '-' + baseAsset + '-' + quotedAsset + '-' + product + '-' + timeFrame, true) + filters.exchange.products.set(exchange + '-' + baseAsset + '-' + quotedAsset + '-' + product, true) + filters.exchange.markets.set(exchange + '-' + baseAsset + '-' + quotedAsset, true) + filters.exchange.list.set(exchange, true) } } } diff --git a/Projects/Superalgos/UI/Function-Libraries/LearningSessionFunctions.js b/Projects/Superalgos/UI/Function-Libraries/LearningSessionFunctions.js index e56e35759..a9ffb2271 100644 --- a/Projects/Superalgos/UI/Function-Libraries/LearningSessionFunctions.js +++ b/Projects/Superalgos/UI/Function-Libraries/LearningSessionFunctions.js @@ -122,7 +122,7 @@ function newSuperalgosFunctionLibraryLearningSessionFunctions() { let session = UI.projects.superalgos.functionLibraries.protocolNode.getProtocolNode(node, false, true, true, false, false, lightingPath) - let dependencyFilter = UI.projects.superalgos.functionLibraries.dependenciesFilter.createFilter(node.tradingSystemReference.payload.referenceParent) + let dependencyFilter = UI.projects.superalgos.functionLibraries.dependenciesFilter.createDependencyFilter(node.tradingSystemReference.payload.referenceParent) /* Raise event to run the session */ let event = { diff --git a/Projects/Superalgos/UI/Function-Libraries/TaskFunctions.js b/Projects/Superalgos/UI/Function-Libraries/TaskFunctions.js index 59da53e38..5a47da8de 100644 --- a/Projects/Superalgos/UI/Function-Libraries/TaskFunctions.js +++ b/Projects/Superalgos/UI/Function-Libraries/TaskFunctions.js @@ -158,6 +158,8 @@ function newSuperalgosFunctionLibraryTaskFunctions() { 'Project Data Products->Project Trading Products->Project Learning Products->' + 'Exchange Data Products->Exchange Trading Products->Exchange Learning Products->' + 'Market Data Products->Market Trading Products->Market Learning Products->' + + 'Market->Market Base Asset->Market Quoted Asset->Asset->' + + 'Exchange Markets->Crypto Exchange->' + 'Data Mine Products->Bot Products->' + 'Data Product Folder->Data Product Folder->Data Product Folder->Data Product Folder->Data Product Folder->' + 'Data Product->Product Definition->' + diff --git a/Projects/Superalgos/UI/Function-Libraries/TradingSessionFunctions.js b/Projects/Superalgos/UI/Function-Libraries/TradingSessionFunctions.js index b591b9c1c..1a1ac95d9 100644 --- a/Projects/Superalgos/UI/Function-Libraries/TradingSessionFunctions.js +++ b/Projects/Superalgos/UI/Function-Libraries/TradingSessionFunctions.js @@ -1,6 +1,6 @@ function newSuperalgosFunctionLibraryTradingSessionFunctions() { thisObject = { - syncronizeSessionWithBackEnd: syncronizeSessionWithBackEnd, + syncronizeSessionWithBackEnd: syncronizeSessionWithBackEnd, runSession: runSession, stopSession: stopSession } @@ -8,7 +8,12 @@ function newSuperalgosFunctionLibraryTradingSessionFunctions() { return thisObject function syncronizeSessionWithBackEnd(node) { - let networkNode = validations(node) + let validationsResult = validations(node) + if (validationsResult === undefined) { + /* If something fails at validations we just quit. */ + return + } + let networkNode = validationsResult.networkNode if (networkNode === undefined) { /* Nodes that do not belong to a network can not get ready. */ return @@ -27,7 +32,7 @@ function newSuperalgosFunctionLibraryTradingSessionFunctions() { function onStatus(message) { eventsServerClient.stopListening(key, eventSubscriptionIdOnStatus, node.id) - if (message.event.status === 'Trading Session Runnning' ) { + if (message.event.status === 'Trading Session Runnning') { node.payload.uiObject.menu.internalClick('Run Trading Session') } } @@ -37,7 +42,12 @@ function newSuperalgosFunctionLibraryTradingSessionFunctions() { } function runSession(node, resume, callBackFunction) { - let networkNode = validations(node) + let validationsResult = validations(node) + if (validationsResult === undefined) { + /* If something fails at validations we just quit. */ + return + } + let networkNode = validationsResult.networkNode if (networkNode === undefined) { /* This means that the validations failed. */ callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) @@ -123,7 +133,17 @@ function newSuperalgosFunctionLibraryTradingSessionFunctions() { let session = UI.projects.superalgos.functionLibraries.protocolNode.getProtocolNode(node, false, true, true, false, false, lightingPath) - let dependencyFilter = UI.projects.superalgos.functionLibraries.dependenciesFilter.createFilter(node.tradingSystemReference.payload.referenceParent) + let defaultExchange = UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(validationsResult.exchange.payload, 'codeName') + let defaultMarket = + UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(validationsResult.market.baseAsset.payload.referenceParent.payload, 'codeName') + + '-' + + UI.projects.superalgos.utilities.nodeConfig.loadPropertyFromNodeConfig(validationsResult.market.quotedAsset.payload.referenceParent.payload, 'codeName') + + let dependencyFilter = UI.projects.superalgos.functionLibraries.dependenciesFilter.createDependencyFilter( + defaultExchange, + defaultMarket, + node.tradingSystemReference.payload.referenceParent + ) /* Raise event to run the session */ let event = { @@ -147,13 +167,18 @@ function newSuperalgosFunctionLibraryTradingSessionFunctions() { } function stopSession(node, callBackFunction) { - let networkNode = validations(node) + let validationsResult = validations(node) + if (validationsResult === undefined) { + /* If something fails at validations we just quit. */ + return + } + let networkNode = validationsResult.networkNode if (networkNode === undefined) { /* This means that the validations failed. */ callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE) return } - + let eventsServerClient = UI.projects.superalgos.spaces.designSpace.workspace.eventsServerClients.get(networkNode.id) let key = node.name + '-' + node.type + '-' + node.id @@ -163,6 +188,9 @@ function newSuperalgosFunctionLibraryTradingSessionFunctions() { } function validations(node) { + + let result = {} + if (node.payload.parentNode === undefined) { node.payload.uiObject.setErrorMessage('Session needs a Process Instance parent to be able to run.') return @@ -183,34 +211,34 @@ function newSuperalgosFunctionLibraryTradingSessionFunctions() { return } - let taskManager = node.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode + result.taskManager = node.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode - if (taskManager.payload.parentNode === undefined) { + if (result.taskManager.payload.parentNode === undefined) { node.payload.uiObject.setErrorMessage('Session needs to be inside Mine Tasks.') return } - if (taskManager.payload.parentNode.payload.parentNode === undefined) { + if (result.taskManager.payload.parentNode.payload.parentNode === undefined) { node.payload.uiObject.setErrorMessage('Session needs to be inside Market Tasks.') return } - if (taskManager.payload.parentNode.payload.parentNode.payload.parentNode === undefined) { + if (result.taskManager.payload.parentNode.payload.parentNode.payload.parentNode === undefined) { node.payload.uiObject.setErrorMessage('Session needs to be inside Exchange Tasks.') return } - if (taskManager.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode === undefined) { + if (result.taskManager.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode === undefined) { node.payload.uiObject.setErrorMessage('Session needs to be inside a Testing or Production Trading Tasks.') return } - if (taskManager.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode === undefined) { + if (result.taskManager.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode.payload.parentNode === undefined) { node.payload.uiObject.setErrorMessage('Session needs to be inside a Network Node.') return } - let networkNode = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(taskManager, 'Network Node', undefined, true, false, true, false) + result.networkNode = UI.projects.superalgos.utilities.meshes.findNodeInNodeMesh(result.taskManager, 'Network Node', undefined, true, false, true, false) if (node.tradingSystemReference === undefined) { node.payload.uiObject.setErrorMessage('Session needs a child Trading System Reference.') @@ -231,6 +259,46 @@ function newSuperalgosFunctionLibraryTradingSessionFunctions() { node.payload.uiObject.setErrorMessage('Trading Engine Reference needs to reference a Trading Engine.') return } - return networkNode + + if (result.taskManager.payload.parentNode.payload.parentNode.payload.referenceParent === undefined) { + node.payload.uiObject.setErrorMessage('Session needs to have a Default Market.') + return + } + + result.market = result.taskManager.payload.parentNode.payload.parentNode.payload.referenceParent + + if (result.market.payload.parentNode === undefined) { + node.payload.uiObject.setErrorMessage('Default Market needs to be a child of Exchange Markets.') + return + } + + if (result.market.payload.parentNode.payload.parentNode === undefined) { + node.payload.uiObject.setErrorMessage('Exchange Markets neeed to be a child of Crypto Exchange.') + return + } + + if (result.market.baseAsset === undefined) { + node.payload.uiObject.setErrorMessage('Default Market needs to have a Base Asset.') + return + } + + if (result.market.quotedAsset === undefined) { + node.payload.uiObject.setErrorMessage('Default Market needs to have a Quoted Asset.') + return + } + + if (result.market.baseAsset.payload.referenceParent === undefined) { + node.payload.uiObject.setErrorMessage('Market Base Asset needs to reference an Asset.') + return + } + + if (result.market.quotedAsset.payload.referenceParent === undefined) { + node.payload.uiObject.setErrorMessage('Market Quoted Asset needs to reference an Asset.') + return + } + + result.exchange = result.market.payload.parentNode.payload.parentNode + + return result } } diff --git a/Projects/Superalgos/UI/Spaces/Top-Space/TopSpace.js b/Projects/Superalgos/UI/Spaces/Top-Space/TopSpace.js index cca8414b0..8fff424c3 100644 --- a/Projects/Superalgos/UI/Spaces/Top-Space/TopSpace.js +++ b/Projects/Superalgos/UI/Spaces/Top-Space/TopSpace.js @@ -24,7 +24,7 @@ function newSuperalgosTopSpace() { logoImage = new Image() loadImage('superalgos-header-background', backgroundImage) - loadImage('sa-beta8-logo-horiz-dark', logoImage) + loadImage('sa-beta9-logo-horiz-dark', logoImage) function loadImage(name, image) { const PATH = 'Images/' diff --git a/Projects/Superalgos/UI/Utilities/Strings.js b/Projects/Superalgos/UI/Utilities/Strings.js index 6a21f9691..6f3c955cc 100644 --- a/Projects/Superalgos/UI/Utilities/Strings.js +++ b/Projects/Superalgos/UI/Utilities/Strings.js @@ -58,7 +58,12 @@ function newSuperalgosUtilitiesStrings() { if (text[i - 1] === '.') { return false } } - if (character === '.') { dotsDetected = true } + if (character === '.') { + dotsDetected = true + if (text[i-1] !== undefined && text[i+1] !== undefined && text[i-1] !== '.' && text[i+1] !== '.'){ + return true + } + } } /* Check that there is at lest one upper case before numbers or dots */ diff --git a/README.md b/README.md index 73391dd5e..dec5b0068 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +# Superalgos Beta 9 + # Getting Started Guide All procedures are the same for Windows, Linux, or Mac OS. diff --git a/UI/Data-Files/src/FileCursor.js b/UI/Data-Files/src/FileCursor.js index 2cae02a22..fdb933c95 100644 --- a/UI/Data-Files/src/FileCursor.js +++ b/UI/Data-Files/src/FileCursor.js @@ -108,11 +108,11 @@ function newFileCursor() { endDateRange = pEndDateRange eventsServerClient = pEventsServerClient - let key = mine.config.codeName + '-' + bot.config.codeName + '-' + product.config.codeName + '-' + dataset.config.codeName + '-' + exchange.name + '-' + market.baseAsset + '/' + market.quotedAsset + let key = mine.config.codeName + '-' + bot.config.codeName + '-' + product.config.codeName + '-' + dataset.config.codeName + '-' + exchange.config.codeName + '-' + market.baseAsset + '/' + market.quotedAsset let callerId = key + '-' + periodName + newUniqueId() eventsServerClient.listenToEvent(key, 'Dataset Updated', undefined, callerId, onResponseDataSet, updateFiles) - key = mine.config.codeName + '-' + bot.config.codeName + '-' + product.config.codeName + '-' + exchange.name + '-' + market.baseAsset + '/' + market.quotedAsset + key = mine.config.codeName + '-' + bot.config.codeName + '-' + product.config.codeName + '-' + exchange.config.codeName + '-' + market.baseAsset + '/' + market.quotedAsset callerId = key + '-' + periodName + newUniqueId() eventsServerClient.listenToEvent(key, 'Data Range Updated', undefined, callerId, onResponseDataRange, updateDataRange) diff --git a/UI/Data-Files/src/FileSequence.js b/UI/Data-Files/src/FileSequence.js index 9ff177f0b..5434e4c64 100644 --- a/UI/Data-Files/src/FileSequence.js +++ b/UI/Data-Files/src/FileSequence.js @@ -88,7 +88,7 @@ function newFileSequence () { callerId = newUniqueId() - let key = mine.config.codeName + '-' + bot.config.codeName + '-' + product.config.codeName + '-' + dataset.config.codeName + '-' + exchange.name + '-' + market.baseAsset + '/' + market.quotedAsset + let key = mine.config.codeName + '-' + bot.config.codeName + '-' + product.config.codeName + '-' + dataset.config.codeName + '-' + exchange.config.codeName + '-' + market.baseAsset + '/' + market.quotedAsset eventsServerClient.listenToEvent(key, 'Dataset Updated', undefined, callerId, onResponse, updateFiles) function onResponse (message) { diff --git a/UI/Data-Files/src/MarketFiles.js b/UI/Data-Files/src/MarketFiles.js index 819ec288f..ccfadcdd2 100644 --- a/UI/Data-Files/src/MarketFiles.js +++ b/UI/Data-Files/src/MarketFiles.js @@ -177,7 +177,7 @@ function newMarketFiles() { } if (filesLoaded + filesNotLoaded === marketFilesPeriods.length) { - let key = mine.config.codeName + '-' + bot.config.codeName + '-' + product.config.codeName + '-' + dataset.config.codeName + '-' + exchange.name + '-' + market.baseAsset + '/' + market.quotedAsset + let key = mine.config.codeName + '-' + bot.config.codeName + '-' + product.config.codeName + '-' + dataset.config.codeName + '-' + exchange.config.codeName + '-' + market.baseAsset + '/' + market.quotedAsset let callerId = key + '-' + periodName + newUniqueId() eventsServerClient.listenToEvent(key, 'Dataset Updated', undefined, callerId, onResponse, updateFiles) diff --git a/run.js b/run.js index dcea2c68b..338678a50 100644 --- a/run.js +++ b/run.js @@ -11,7 +11,7 @@ if ( console.log('Superalgos') console.log('') - console.log('VERSION: Beta 8') + console.log('VERSION: Beta 9') console.log('') console.log('WEB: https://www.superalgos.org') console.log('')