272 lines
14 KiB
JavaScript
272 lines
14 KiB
JavaScript
exports.newFoundationsProcessModulesDataDependencies = function (processIndex) {
|
|
/*
|
|
This module maintains 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 circumstances 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.
|
|
|
|
It also maintains 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 maintains 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 = {
|
|
filters: undefined,
|
|
defaultExchange: undefined,
|
|
defaultMarket: undefined,
|
|
curatedDependencyNodeArray: undefined,
|
|
dataSetsModulesArray: [],
|
|
initialize: initialize,
|
|
finalize: finalize
|
|
}
|
|
|
|
thisObject.filters = {
|
|
market: {
|
|
list: new Map()
|
|
},
|
|
exchange: {
|
|
list: new Map(),
|
|
markets: new Map(),
|
|
products: new Map(),
|
|
timeFrames: new Map()
|
|
}
|
|
}
|
|
|
|
return thisObject
|
|
|
|
function initialize(callBackFunction) {
|
|
try {
|
|
/* Basic Validations */
|
|
if (TS.projects.foundations.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processDependencies !== undefined) {
|
|
/*
|
|
First we will get all the data dependencies of the bot, as defined at the Trading Mine.
|
|
*/
|
|
thisObject.curatedDependencyNodeArray = TS.projects.visualScripting.utilities.nodeFunctions.nodeBranchToArray(TS.projects.foundations.globals.taskConstants.TASK_NODE.bot.processes[processIndex].referenceParent.processDependencies, 'Data Dependency')
|
|
if (thisObject.curatedDependencyNodeArray.length === 0) {
|
|
TS.projects.foundations.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.foundations.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
|
return
|
|
}
|
|
/*
|
|
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.curatedDependencyNodeArray = TS.projects.visualScripting.utilities.nodeFunctions.filterOutNodeWihtoutReferenceParentFromNodeArray(thisObject.curatedDependencyNodeArray)
|
|
|
|
} else {
|
|
TS.projects.foundations.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.foundations.globals.standardResponses.DEFAULT_OK_RESPONSE)
|
|
return
|
|
}
|
|
|
|
if (thisObject.curatedDependencyNodeArray.length === 0) {
|
|
|
|
// We allow old indicators not to declare their data dependencies.
|
|
callBackFunction(TS.projects.foundations.globals.standardResponses.DEFAULT_OK_RESPONSE)
|
|
return
|
|
}
|
|
|
|
/*
|
|
Store here the default exchange and market.
|
|
*/
|
|
thisObject.defaultExchange = TS.projects.foundations.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.config.codeName
|
|
thisObject.defaultMarket =
|
|
TS.projects.foundations.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName +
|
|
"-" +
|
|
TS.projects.foundations.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName
|
|
|
|
/* Session based dependency thisObject.filters */
|
|
let receivedDependencyFilters = TS.projects.foundations.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)
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
In case we do not receive any filters, like in the case of Indicators and Sensors,
|
|
or simply because the Learning System is still empty,
|
|
we need to add the default exchange and market to these maps in order
|
|
for the following sections to work, and later we at least have candles at the
|
|
Learning Simulation.
|
|
*/
|
|
thisObject.filters.market.list.set(thisObject.defaultMarket, true)
|
|
|
|
thisObject.filters.exchange.list.set(thisObject.defaultExchange, true)
|
|
thisObject.filters.exchange.markets.set(thisObject.defaultExchange + '-' + thisObject.defaultMarket, true)
|
|
|
|
/*
|
|
For each dependency declared at the curatedDependencyNodeArray, we will initialize a
|
|
DataSet as part of this initialization process.
|
|
*/
|
|
let alreadyCalledBack = false
|
|
|
|
/*
|
|
The current curatedDependencyNodeArray that we have includes all the dependencies declared 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
|
|
this task is running, that is storing the data associated to this dependency. The way we use to filter this
|
|
out is by analyzing 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 = []
|
|
|
|
let exchangeList = Array.from(thisObject.filters.exchange.list.keys())
|
|
let marketList = Array.from(thisObject.filters.market.list.keys())
|
|
|
|
/*
|
|
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 {
|
|
/*
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
|
|
if (alreadyCalledBack === false) {
|
|
alreadyCalledBack = true
|
|
thisObject.curatedDependencyNodeArray = newNodeArray
|
|
callBackFunction(TS.projects.foundations.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 exact 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
|
|
}
|
|
let foundAtDependencyFilters = false
|
|
/*
|
|
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
|
|
/*
|
|
We will filter out all the data dependencies which are not at the filters, except for candles,
|
|
because we will need the candles dataset to run the simulation.
|
|
*/
|
|
if (dataDependency.referenceParent.parentNode.config.codeName === 'Candles') {
|
|
foundAtDependencyFilters = true
|
|
}
|
|
/*
|
|
We will consider that the user might use the singularVariableName or the pluralVariableName
|
|
as well.
|
|
*/
|
|
product = dataDependency.referenceParent.parentNode.config.singularVariableName
|
|
if (thisObject.filters.exchange.products.get(exchange + '-' + market + '-' + product) === true) {
|
|
foundAtDependencyFilters = true
|
|
}
|
|
product = dataDependency.referenceParent.parentNode.config.pluralVariableName
|
|
if (thisObject.filters.exchange.products.get(exchange + '-' + market + '-' + product) === true) {
|
|
foundAtDependencyFilters = true
|
|
}
|
|
if (foundAtDependencyFilters === true) {
|
|
addDataSet(exchange, market)
|
|
}
|
|
} else {
|
|
addDataSet(exchange, market)
|
|
}
|
|
|
|
function addDataSet(exchange, market) {
|
|
|
|
let dataSetModule = TS.projects.foundations.processModules.dataset.newFoundationsProcessModulesDataset(processIndex)
|
|
dataSetModule.initialize(exchange, market, dataDependency, onInitilized)
|
|
|
|
function onInitilized(err, wasInitialized) {
|
|
|
|
if (err.result !== TS.projects.foundations.globals.standardResponses.DEFAULT_OK_RESPONSE.result) {
|
|
TS.projects.foundations.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)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
} catch (err) {
|
|
TS.projects.foundations.globals.processVariables.VARIABLES_BY_PROCESS_INDEX_MAP.get(processIndex).UNEXPECTED_ERROR = err
|
|
TS.projects.foundations.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.foundations.globals.standardResponses.DEFAULT_FAIL_RESPONSE)
|
|
}
|
|
}
|
|
|
|
function finalize() {
|
|
for (let i = 0; i < thisObject.dataSetsModulesArray.length; i++) {
|
|
let dataSetModule = thisObject.dataSetsModulesArray[i]
|
|
dataSetModule.finalize()
|
|
}
|
|
thisObject.dataSetsModulesArray = undefined
|
|
thisObject.curatedDependencyNodeArray = undefined
|
|
thisObject.filters = undefined
|
|
thisObject.defaultExchange = undefined
|
|
thisObject.defaultMarket = undefined
|
|
bot = undefined
|
|
}
|
|
}
|