Ai Bot Node implemented
This commit is contained in:
1 parent
3b9dc370b9
commit
b2ed704745
30 files changed
+393
-299
No files matched your search
@@ -99,6 +99,9 @@
|
||||
if (botNode === undefined) {
|
||||
botNode = global.FIND_NODE_IN_NODE_MESH(outputDatasetNode, 'Trading Bot')
|
||||
}
|
||||
if (botNode === undefined) {
|
||||
botNode = global.FIND_NODE_IN_NODE_MESH(outputDatasetNode, 'AI Bot')
|
||||
}
|
||||
if (botNode === undefined) {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> Product Definition not attached to a Bot. Product Definition = ");
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
|
||||
+7
-3
@@ -80,10 +80,14 @@ exports.newDebugLog = function newDebugLog() {
|
||||
|
||||
let filePath = thisObject.bot.filePathRoot + "/Logs/" + thisObject.bot.process + "/"
|
||||
|
||||
if (thisObject.bot.SESSION !== undefined) {
|
||||
filePath = filePath + thisObject.bot.SESSION.folderName + "/" + executionDatetime;
|
||||
if (thisObject.bot.TRADING_SESSION !== undefined) {
|
||||
filePath = filePath + thisObject.bot.TRADING_SESSION.folderName + "/" + executionDatetime;
|
||||
} else {
|
||||
filePath = filePath + executionDatetime;
|
||||
if (thisObject.bot.AI_SESSION !== undefined) {
|
||||
filePath = filePath + thisObject.bot.AI_SESSION.folderName + "/" + executionDatetime;
|
||||
} else {
|
||||
filePath = filePath + executionDatetime;
|
||||
}
|
||||
}
|
||||
|
||||
if (thisObject.bot.debug.year !== undefined) {
|
||||
|
||||
@@ -21,7 +21,7 @@ exports.newAnnouncements = function newAnnouncements(bot, logger) {
|
||||
function finalize() {
|
||||
tradingSystem = undefined
|
||||
tradingEngine = undefined
|
||||
bot.SESSION.messagesSent = undefined
|
||||
bot.TRADING_SESSION.messagesSent = undefined
|
||||
}
|
||||
|
||||
function makeAnnoucements(node) {
|
||||
@@ -44,8 +44,8 @@ exports.newAnnouncements = function newAnnouncements(bot, logger) {
|
||||
text = tradingSystem.formulas.get(announcement.formula.id)
|
||||
}
|
||||
|
||||
if (bot.SESSION.socialBots !== undefined) {
|
||||
bot.SESSION.socialBots.announce(text)
|
||||
if (bot.TRADING_SESSION.socialBots !== undefined) {
|
||||
bot.TRADING_SESSION.socialBots.announce(text)
|
||||
tradingSystem.announcements.push([announcement.id, text])
|
||||
} else {
|
||||
tradingSystem.errors.push([announcement.id, 'Could not announce because session does not have Social Bots.'])
|
||||
|
||||
@@ -23,7 +23,7 @@ exports.newOrdersCalculations = function newOrdersCalculations(bot, logger) {
|
||||
return thisObject
|
||||
|
||||
function initialize() {
|
||||
sessionParameters = bot.SESSION.parameters
|
||||
sessionParameters = bot.TRADING_SESSION.parameters
|
||||
tradingEngine = bot.simulationState.tradingEngine
|
||||
tradingSystem = bot.simulationState.tradingSystem
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ exports.newOrdersSimulations = function newOrdersSimulations(bot, logger) {
|
||||
return thisObject
|
||||
|
||||
function initialize() {
|
||||
sessionParameters = bot.SESSION.parameters
|
||||
sessionParameters = bot.TRADING_SESSION.parameters
|
||||
tradingEngine = bot.simulationState.tradingEngine
|
||||
tradingSystem = bot.simulationState.tradingSystem
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ exports.newSnapshots = function newSnapshots(bot, logger) {
|
||||
function initialize() {
|
||||
tradingEngine = bot.simulationState.tradingEngine
|
||||
tradingSystem = bot.simulationState.tradingSystem
|
||||
sessionParameters = bot.SESSION.parameters
|
||||
sessionParameters = bot.TRADING_SESSION.parameters
|
||||
}
|
||||
|
||||
function finalize() {
|
||||
@@ -322,7 +322,7 @@ exports.newSnapshots = function newSnapshots(bot, logger) {
|
||||
fileContent = "" + fileContent + "";
|
||||
|
||||
let fileName = pFileName + '.csv';
|
||||
let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + SNAPSHOTS_FOLDER_NAME;
|
||||
let filePath = bot.filePathRoot + "/Output/" + bot.TRADING_SESSION.folderName + "/" + SNAPSHOTS_FOLDER_NAME;
|
||||
filePath += '/' + fileName
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
|
||||
|
||||
@@ -25,7 +25,7 @@ exports.newTradingEngine = function newTradingEngine(bot, logger) {
|
||||
function initialize() {
|
||||
|
||||
tradingEngine = bot.simulationState.tradingEngine
|
||||
sessionParameters = bot.SESSION.parameters
|
||||
sessionParameters = bot.TRADING_SESSION.parameters
|
||||
|
||||
initializeNodeMap(tradingEngine)
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ exports.newTradingEpisode = function newTradingEpisode(bot, logger, tradingEngin
|
||||
function initialize() {
|
||||
tradingSystem = bot.simulationState.tradingSystem
|
||||
tradingEngine = bot.simulationState.tradingEngine
|
||||
sessionParameters = bot.SESSION.parameters
|
||||
sessionParameters = bot.TRADING_SESSION.parameters
|
||||
}
|
||||
|
||||
function finalize() {
|
||||
|
||||
@@ -24,7 +24,7 @@ exports.newTradingExecution = function newTradingExecution(bot, logger, tradingE
|
||||
function initialize() {
|
||||
tradingSystem = bot.simulationState.tradingSystem
|
||||
tradingEngine = bot.simulationState.tradingEngine
|
||||
sessionParameters = bot.SESSION.parameters
|
||||
sessionParameters = bot.TRADING_SESSION.parameters
|
||||
|
||||
tradingOrdersModule.initialize()
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
|
||||
function initialize() {
|
||||
tradingSystem = bot.simulationState.tradingSystem
|
||||
tradingEngine = bot.simulationState.tradingEngine
|
||||
sessionParameters = bot.SESSION.parameters
|
||||
sessionParameters = bot.TRADING_SESSION.parameters
|
||||
|
||||
exchangeAPIModule.initialize()
|
||||
announcementsModule.initialize()
|
||||
@@ -476,7 +476,7 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
|
||||
async function createOrderAtExchange(tradingSystemOrder, tradingEngineOrder) {
|
||||
|
||||
/* Filter by Session Type */
|
||||
switch (bot.SESSION.type) {
|
||||
switch (bot.TRADING_SESSION.type) {
|
||||
case 'Backtesting Session': {
|
||||
return true
|
||||
}
|
||||
@@ -503,7 +503,7 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
|
||||
async function checkExchangeEvents(tradingEngineStage, tradingSystemOrder, tradingEngineOrder) {
|
||||
|
||||
/* Filter by Session Type */
|
||||
switch (bot.SESSION.type) {
|
||||
switch (bot.TRADING_SESSION.type) {
|
||||
case 'Backtesting Session': {
|
||||
return true
|
||||
}
|
||||
@@ -613,7 +613,7 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
|
||||
function simulateCheckExchangeEvents(tradingEngineStage, tradingSystemOrder, tradingEngineOrder) {
|
||||
|
||||
/* Filter by Session Type */
|
||||
switch (bot.SESSION.type) {
|
||||
switch (bot.TRADING_SESSION.type) {
|
||||
case 'Backtesting Session': {
|
||||
break
|
||||
}
|
||||
@@ -839,7 +839,7 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
|
||||
function simulateCancelOrder(tradingEngineStage, tradingSystemOrder, tradingEngineOrder, exitType) {
|
||||
|
||||
/* Filter by Session Type */
|
||||
switch (bot.SESSION.type) {
|
||||
switch (bot.TRADING_SESSION.type) {
|
||||
case 'Backtesting Session': {
|
||||
break
|
||||
}
|
||||
@@ -870,7 +870,7 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
|
||||
async function exchangeCancelOrder(tradingEngineStage, tradingSystemOrder, tradingEngineOrder, exitType) {
|
||||
|
||||
/* Filter by Session Type */
|
||||
switch (bot.SESSION.type) {
|
||||
switch (bot.TRADING_SESSION.type) {
|
||||
case 'Backtesting Session': {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, tradingEngineM
|
||||
This module will load if necesary all the data outputs so that they can be appended with new
|
||||
records if needed. After running the simulation, it will save all the data outputs.
|
||||
*/
|
||||
const MODULE_NAME = 'Trading Bot'
|
||||
const MODULE_NAME = 'Trading Output'
|
||||
|
||||
let thisObject = {
|
||||
initialize: initialize,
|
||||
@@ -133,7 +133,7 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, tradingEngineM
|
||||
if (dataset.config.type === 'Market Files') {
|
||||
|
||||
let fileName = 'Data.json'
|
||||
let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel
|
||||
let filePath = bot.filePathRoot + '/Output/' + bot.TRADING_SESSION.folderName + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel
|
||||
|
||||
await readOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
|
||||
}
|
||||
@@ -149,7 +149,7 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, tradingEngineM
|
||||
|
||||
let dateForPath = tradingProcessDate.getUTCFullYear() + '/' + utilities.pad(tradingProcessDate.getUTCMonth() + 1, 2) + '/' + utilities.pad(tradingProcessDate.getUTCDate(), 2);
|
||||
let fileName = 'Data.json'
|
||||
let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel + "/" + dateForPath
|
||||
let filePath = bot.filePathRoot + '/Output/' + bot.TRADING_SESSION.folderName + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel + "/" + dateForPath
|
||||
|
||||
await readOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
|
||||
}
|
||||
@@ -190,7 +190,7 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, tradingEngineM
|
||||
if (dataset.config.type === 'Market Files') {
|
||||
|
||||
let fileName = 'Data.json'
|
||||
let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel
|
||||
let filePath = bot.filePathRoot + '/Output/' + bot.TRADING_SESSION.folderName + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel
|
||||
|
||||
await writeOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
|
||||
}
|
||||
@@ -206,7 +206,7 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, tradingEngineM
|
||||
|
||||
let dateForPath = tradingProcessDate.getUTCFullYear() + '/' + utilities.pad(tradingProcessDate.getUTCMonth() + 1, 2) + '/' + utilities.pad(tradingProcessDate.getUTCDate(), 2);
|
||||
let fileName = 'Data.json'
|
||||
let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel + "/" + dateForPath
|
||||
let filePath = bot.filePathRoot + '/Output/' + bot.TRADING_SESSION.folderName + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel + "/" + dateForPath
|
||||
|
||||
await writeOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
|
||||
function initialize() {
|
||||
tradingSystem = bot.simulationState.tradingSystem
|
||||
tradingEngine = bot.simulationState.tradingEngine
|
||||
sessionParameters = bot.SESSION.parameters
|
||||
sessionParameters = bot.TRADING_SESSION.parameters
|
||||
}
|
||||
|
||||
function finalize() {
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
This variable tell us which day we are standing at, specially while working
|
||||
with Daily Files. From this Date is that we are going to load the Daily Files.
|
||||
*/
|
||||
bot.simulationState.tradingEngine.current.episode.processDate.value = global.REMOVE_TIME(bot.SESSION.parameters.timeRange.config.initialDatetime).valueOf()
|
||||
bot.simulationState.tradingEngine.current.episode.processDate.value = global.REMOVE_TIME(bot.TRADING_SESSION.parameters.timeRange.config.initialDatetime).valueOf()
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -119,7 +119,7 @@
|
||||
await processSingleFiles()
|
||||
|
||||
if (await processMarketFiles() === false) {
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Waiting for Data Mining to be run')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Waiting for Data Mining to be run')
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
@@ -141,17 +141,17 @@
|
||||
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.
|
||||
*/
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Waking up')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Waking up')
|
||||
buildCharts(chart)
|
||||
|
||||
if (checkThereAreCandles(chart) === true) {
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Running')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Running')
|
||||
await generateOutput(chart)
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Saving')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Saving')
|
||||
await writeProcessFiles()
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Sleeping')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Sleeping')
|
||||
} else {
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Waiting for Data Mining to be up to date. No candles found at.')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Waiting for Data Mining to be up to date. No candles found at.')
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
@@ -159,7 +159,7 @@
|
||||
} else {
|
||||
/* We are processing Daily Files */
|
||||
do {
|
||||
global.EMIT_SESSION_STATUS(bot.SESSION_STATUS, bot.sessionKey)
|
||||
global.EMIT_SESSION_STATUS(bot.TRADING_SESSION_STATUS, bot.TRADING_SESSIONKey)
|
||||
/*
|
||||
We update the Trading Process Date with the date calculated at the simulation.
|
||||
We will use this date to load indicator and output files. After that we will
|
||||
@@ -171,9 +171,9 @@
|
||||
if (checkStopTaskGracefully() === false) { break }
|
||||
if (checkStopProcessing() === false) { break }
|
||||
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Waking up')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Waking up')
|
||||
if (await processDailyFiles() === false) {
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Waiting for Data Mining to be run')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Waiting for Data Mining to be run')
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
@@ -186,13 +186,13 @@
|
||||
The process of generating the output includes the trading simulation.
|
||||
*/
|
||||
if (checkThereAreCandles(chart) === true) {
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Running')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Running')
|
||||
await generateOutput(chart)
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Saving')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Saving')
|
||||
await writeProcessFiles()
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Sleeping')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Sleeping')
|
||||
} else {
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Waiting for Data Mining to be up to date')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Waiting for Data Mining to be up to date')
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
@@ -219,7 +219,7 @@
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE)
|
||||
|
||||
function checkThereAreCandles(chart) {
|
||||
let sessionParameters = bot.SESSION.parameters
|
||||
let sessionParameters = bot.TRADING_SESSION.parameters
|
||||
let propertyName = 'at' + sessionParameters.timeFrame.config.label.replace('-', '')
|
||||
let candles = chart[propertyName].candles
|
||||
|
||||
@@ -236,7 +236,7 @@
|
||||
let statusReport;
|
||||
|
||||
/* We are going to use the start date as beging of market date. */
|
||||
contextVariables.dateBeginOfMarket = global.REMOVE_TIME(bot.SESSION.parameters.timeRange.config.initialDatetime)
|
||||
contextVariables.dateBeginOfMarket = global.REMOVE_TIME(bot.TRADING_SESSION.parameters.timeRange.config.initialDatetime)
|
||||
/*
|
||||
Here we get the status report from the bot who knows which is the end of the market.
|
||||
*/
|
||||
@@ -371,7 +371,7 @@
|
||||
|
||||
dataFiles = new Map();
|
||||
|
||||
if (bot.SESSION.parameters.timeFrame.config.label === timeFrameLabel) {
|
||||
if (bot.TRADING_SESSION.parameters.timeFrame.config.label === timeFrameLabel) {
|
||||
currentTimeFrame = global.marketFilesPeriods[n][0];
|
||||
currentTimeFrameLabel = global.marketFilesPeriods[n][1];
|
||||
}
|
||||
@@ -384,7 +384,7 @@
|
||||
}
|
||||
|
||||
if (dataDependenciesModule.isItADepenency(timeFrameLabel, datasetModule.node.parentNode.config.singularVariableName) !== true) {
|
||||
if (!(bot.SESSION.parameters.timeFrame.config.label === timeFrameLabel && datasetModule.node.parentNode.config.pluralVariableName === 'candles')) {
|
||||
if (!(bot.TRADING_SESSION.parameters.timeFrame.config.label === timeFrameLabel && datasetModule.node.parentNode.config.pluralVariableName === 'candles')) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -431,8 +431,8 @@
|
||||
let dataRecord = dataFile[i]
|
||||
let begin = dataRecord[beginIndex]
|
||||
let end = dataRecord[endIndex]
|
||||
if (end + timeFrame < bot.SESSION.parameters.timeRange.config.initialDatetime - 1) { continue } // /1 because we need the previous closed element
|
||||
if (begin > bot.SESSION.parameters.timeRange.config.finalDatetime) { continue }
|
||||
if (end + timeFrame < bot.TRADING_SESSION.parameters.timeRange.config.initialDatetime - 1) { continue } // /1 because we need the previous closed element
|
||||
if (begin > bot.TRADING_SESSION.parameters.timeRange.config.finalDatetime) { continue }
|
||||
result.push(dataRecord)
|
||||
}
|
||||
return result
|
||||
@@ -468,7 +468,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (bot.SESSION.parameters.timeFrame.config.label === timeFrameLabel) {
|
||||
if (bot.TRADING_SESSION.parameters.timeFrame.config.label === timeFrameLabel) {
|
||||
currentTimeFrame = global.dailyFilePeriods[n][0];
|
||||
currentTimeFrameLabel = global.dailyFilePeriods[n][1];
|
||||
}
|
||||
@@ -488,7 +488,7 @@
|
||||
}
|
||||
|
||||
if (dataDependenciesModule.isItADepenency(timeFrameLabel, datasetModule.node.parentNode.config.singularVariableName) !== true) {
|
||||
if (!(bot.SESSION.parameters.timeFrame.config.label === timeFrameLabel && datasetModule.node.parentNode.config.pluralVariableName === 'candles')) {
|
||||
if (!(bot.TRADING_SESSION.parameters.timeFrame.config.label === timeFrameLabel && datasetModule.node.parentNode.config.pluralVariableName === 'candles')) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -653,7 +653,7 @@
|
||||
|
||||
let fileContent = JSON.stringify(dataRange);
|
||||
let fileName = '/Data.Range.json';
|
||||
let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + productCodeName + "/" + 'Multi-Period-Daily' + fileName;
|
||||
let filePath = bot.filePathRoot + "/Output/" + bot.TRADING_SESSION.folderName + "/" + productCodeName + "/" + 'Multi-Period-Daily' + fileName;
|
||||
|
||||
let response = await fileStorage.asyncCreateTextFile(filePath, fileContent + '\n')
|
||||
|
||||
@@ -692,7 +692,7 @@
|
||||
let fileContent = JSON.stringify(timeFramesArray)
|
||||
let fileName = '/Time.Frames.json';
|
||||
|
||||
let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + productCodeName + "/" + processType + fileName;
|
||||
let filePath = bot.filePathRoot + "/Output/" + bot.TRADING_SESSION.folderName + "/" + productCodeName + "/" + processType + fileName;
|
||||
|
||||
let response = await fileStorage.asyncCreateTextFile(filePath, fileContent + '\n')
|
||||
if (response.err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
@@ -728,12 +728,12 @@
|
||||
|
||||
function checkIfSessionMustStop() {
|
||||
|
||||
if (bot.SESSION.type === 'Backtesting Session') {
|
||||
if (bot.TRADING_SESSION.type === 'Backtesting Session') {
|
||||
/*
|
||||
Backtests needs only one execution of this process to complete.
|
||||
*/
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[IMPORTANT] checkIfSessionMustStop -> Backtesting Session Finished. Stopping the Session now. ') }
|
||||
bot.SESSION.stop('Backtesting Session Finished.')
|
||||
bot.TRADING_SESSION.stop('Backtesting Session Finished.')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ exports.newTradingRecords = function newTradingRecords(bot, logger) {
|
||||
function initialize(pOutputDatasetsMap) {
|
||||
tradingEngine = bot.simulationState.tradingEngine
|
||||
tradingSystem = bot.simulationState.tradingSystem
|
||||
sessionParameters = bot.SESSION.parameters
|
||||
sessionParameters = bot.TRADING_SESSION.parameters
|
||||
outputDatasetsMap = pOutputDatasetsMap // These are the files turned into arrays, stored in a Map by Product codeName.
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, tradin
|
||||
the execution at each loop cycle of the Trading System Protocol.
|
||||
*/
|
||||
const FULL_LOG = true
|
||||
const MODULE_NAME = 'Trading Simulation -> ' + bot.SESSION.name
|
||||
const MODULE_NAME = 'Trading Simulation -> ' + bot.TRADING_SESSION.name
|
||||
|
||||
let thisObject = {
|
||||
finalize: finalize,
|
||||
@@ -28,7 +28,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, tradin
|
||||
|
||||
let tradingSystem = bot.simulationState.tradingSystem
|
||||
let tradingEngine = bot.simulationState.tradingEngine
|
||||
let sessionParameters = bot.SESSION.parameters
|
||||
let sessionParameters = bot.TRADING_SESSION.parameters
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> initialDatetime = ' + sessionParameters.timeRange.config.initialDatetime) }
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> finalDatetime = ' + sessionParameters.timeRange.config.finalDatetime) }
|
||||
@@ -71,7 +71,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, tradin
|
||||
This will happen when the sessionParameters.timeRange.config.initialDatetime is beyond the last candle available,
|
||||
meaning that the dataSet needs to be updated with more up-to-date data.
|
||||
*/
|
||||
bot.SESSION.stop('Data is not up-to-date enough. Please start the Masters Data Mining Operation.')
|
||||
bot.TRADING_SESSION.stop('Data is not up-to-date enough. Please start the Masters Data Mining Operation.')
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[IMPORTANT] runSimulation -> Data is not up-to-date enough. Stopping the Session now. ') }
|
||||
return
|
||||
}
|
||||
@@ -210,7 +210,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, tradin
|
||||
if (checkFinalDatetime() === false) {
|
||||
closeEpisode('Final Datetime Reached')
|
||||
breakLoop = true
|
||||
bot.SESSION.stop('Final Datetime Reached')
|
||||
bot.TRADING_SESSION.stop('Final Datetime Reached')
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[IMPORTANT] runSimulation -> Final Datetime Reached. Stopping the Session now. ') }
|
||||
return
|
||||
}
|
||||
@@ -218,7 +218,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, tradin
|
||||
if (checkMinimunAndMaximunBalance() === false) {
|
||||
closeEpisode('Min or Max Balance Reached')
|
||||
breakLoop = true
|
||||
bot.SESSION.stop('Min or Max Balance Reached')
|
||||
bot.TRADING_SESSION.stop('Min or Max Balance Reached')
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[IMPORTANT] runSimulation -> Min or Max Balance Reached. Stopping the Session now. ') }
|
||||
return
|
||||
}
|
||||
@@ -276,7 +276,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, tradin
|
||||
|
||||
let processingDate = heartBeatDate.getUTCFullYear() + '-' + utilities.pad(heartBeatDate.getUTCMonth() + 1, 2) + '-' + utilities.pad(heartBeatDate.getUTCDate(), 2)
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Simulation ' + bot.sessionKey + ' Loop # ' + tradingEngine.current.episode.candle.index.value + ' @ ' + processingDate) }
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Simulation ' + bot.TRADING_SESSIONKey + ' Loop # ' + tradingEngine.current.episode.candle.index.value + ' @ ' + processingDate) }
|
||||
|
||||
/* Logging to console and disk */
|
||||
if (global.areEqualDates(currentDate, new Date()) === false) {
|
||||
|
||||
@@ -47,7 +47,7 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
|
||||
function initialize() {
|
||||
tradingSystem = bot.simulationState.tradingSystem
|
||||
tradingEngine = bot.simulationState.tradingEngine
|
||||
sessionParameters = bot.SESSION.parameters
|
||||
sessionParameters = bot.TRADING_SESSION.parameters
|
||||
|
||||
tradingStrategyModule.initialize()
|
||||
tradingPositionModule.initialize()
|
||||
@@ -160,7 +160,7 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
|
||||
announcementsModule.makeAnnoucements(triggerStage.triggerOn)
|
||||
announcementsModule.makeAnnoucements(triggerStage)
|
||||
|
||||
if (bot.SESSION.type === 'Backtesting Session') {
|
||||
if (bot.TRADING_SESSION.type === 'Backtesting Session') {
|
||||
if (sessionParameters.snapshots !== undefined) {
|
||||
if (sessionParameters.snapshots.config.strategy === true) {
|
||||
snapshotsModule.strategyEntry()
|
||||
@@ -245,7 +245,7 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
|
||||
announcementsModule.makeAnnoucements(triggerStage.takePosition)
|
||||
announcementsModule.makeAnnoucements(strategy.openStage)
|
||||
|
||||
if (bot.SESSION.type === 'Backtesting Session') {
|
||||
if (bot.TRADING_SESSION.type === 'Backtesting Session') {
|
||||
if (sessionParameters.snapshots !== undefined) {
|
||||
if (sessionParameters.snapshots.config.position === true) {
|
||||
snapshotsModule.positionEntry()
|
||||
@@ -856,7 +856,7 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
|
||||
|
||||
function closePositionAndStrategy() {
|
||||
/* Taking Position Snapshot */
|
||||
if (bot.SESSION.type === 'Backtesting Session') {
|
||||
if (bot.TRADING_SESSION.type === 'Backtesting Session') {
|
||||
if (sessionParameters.snapshots !== undefined) {
|
||||
if (sessionParameters.snapshots.config.position === true) {
|
||||
snapshotsModule.positionExit()
|
||||
@@ -865,7 +865,7 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
|
||||
}
|
||||
|
||||
/* Taking Strategy Snapshot */
|
||||
if (bot.SESSION.type === 'Backtesting Session') {
|
||||
if (bot.TRADING_SESSION.type === 'Backtesting Session') {
|
||||
if (sessionParameters.snapshots !== undefined) {
|
||||
if (sessionParameters.snapshots.config.strategy === true) {
|
||||
snapshotsModule.strategyExit()
|
||||
|
||||
@@ -19,7 +19,7 @@ exports.newTradingStrategy = function newTradingStrategy(bot, logger, tradingEng
|
||||
|
||||
function initialize() {
|
||||
tradingEngine = bot.simulationState.tradingEngine
|
||||
sessionParameters = bot.SESSION.parameters
|
||||
sessionParameters = bot.TRADING_SESSION.parameters
|
||||
}
|
||||
|
||||
function finalize() {
|
||||
|
||||
@@ -28,7 +28,7 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
function initialize() {
|
||||
tradingSystem = bot.simulationState.tradingSystem
|
||||
tradingEngine = bot.simulationState.tradingEngine
|
||||
sessionParameters = bot.SESSION.parameters
|
||||
sessionParameters = bot.TRADING_SESSION.parameters
|
||||
|
||||
tradingSystem.conditions = new Map()
|
||||
tradingSystem.formulas = new Map()
|
||||
|
||||
@@ -32,6 +32,9 @@
|
||||
if (botNode === undefined) {
|
||||
botNode = global.FIND_NODE_IN_NODE_MESH(outputDataset, 'Sensor Bot')
|
||||
}
|
||||
if (botNode === undefined) {
|
||||
botNode = global.FIND_NODE_IN_NODE_MESH(outputDataset, 'AI Bot')
|
||||
}
|
||||
|
||||
/* Some validations to verify that everything is in place. */
|
||||
if (outputDataset.referenceParent !== undefined) {
|
||||
@@ -119,6 +122,9 @@
|
||||
if (botNode === undefined) {
|
||||
botNode = global.FIND_NODE_IN_NODE_MESH(outputDataset, 'Sensor Bot')
|
||||
}
|
||||
if (botNode === undefined) {
|
||||
botNode = global.FIND_NODE_IN_NODE_MESH(outputDataset, 'AI Bot')
|
||||
}
|
||||
|
||||
/* Some validations to verify that everything is in place. */
|
||||
if (outputDataset.referenceParent !== undefined) {
|
||||
|
||||
@@ -560,17 +560,17 @@ exports.newAiBot = function newAiBot(bot, parentLogger) {
|
||||
if (processConfig.waitsForExecutionFinishedEvent === true) {
|
||||
waitTime = 0
|
||||
} else {
|
||||
switch (bot.SESSION.type) {
|
||||
switch (bot.AI_SESSION.type) {
|
||||
case 'Live Trading Session': {
|
||||
waitTime = bot.SESSION.parameters.timeFrame.config.value
|
||||
waitTime = bot.AI_SESSION.parameters.timeFrame.config.value
|
||||
break
|
||||
}
|
||||
case 'Fordward Tessting Session': {
|
||||
waitTime = bot.SESSION.parameters.timeFrame.config.value
|
||||
waitTime = bot.AI_SESSION.parameters.timeFrame.config.value
|
||||
break
|
||||
}
|
||||
case 'Paper Trading Session': {
|
||||
waitTime = bot.SESSION.parameters.timeFrame.config.value
|
||||
waitTime = bot.AI_SESSION.parameters.timeFrame.config.value
|
||||
break
|
||||
}
|
||||
case 'Backtesting Session': {
|
||||
|
||||
@@ -25,7 +25,7 @@ exports.newMarkovDecisionProcess = function newMarkovDecisionProcess(bot, logger
|
||||
function initialize() {
|
||||
|
||||
tradingEngine = bot.simulationState.tradingEngine
|
||||
sessionParameters = bot.SESSION.parameters
|
||||
sessionParameters = bot.AI_SESSION.parameters
|
||||
|
||||
initializeNodeMap(tradingEngine)
|
||||
|
||||
|
||||
@@ -103,7 +103,7 @@ exports.newTrainingProcess = function newTrainingProcess(bot, logger, UTILITIES)
|
||||
This variable tell us which day we are standing at, specially while working
|
||||
with Daily Files. From this Date is that we are going to load the Daily Files.
|
||||
*/
|
||||
bot.simulationState.tradingEngine.current.episode.processDate.value = global.REMOVE_TIME(bot.SESSION.parameters.timeRange.config.initialDatetime).valueOf()
|
||||
bot.simulationState.tradingEngine.current.episode.processDate.value = global.REMOVE_TIME(bot.TRADING_SESSION.parameters.timeRange.config.initialDatetime).valueOf()
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -119,7 +119,7 @@ exports.newTrainingProcess = function newTrainingProcess(bot, logger, UTILITIES)
|
||||
await processSingleFiles()
|
||||
|
||||
if (await processMarketFiles() === false) {
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Waiting for Data Mining to be run')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Waiting for Data Mining to be run')
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
@@ -141,17 +141,17 @@ exports.newTrainingProcess = function newTrainingProcess(bot, logger, UTILITIES)
|
||||
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.
|
||||
*/
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Waking up')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Waking up')
|
||||
buildCharts(chart)
|
||||
|
||||
if (checkThereAreCandles(chart) === true) {
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Running')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Running')
|
||||
await generateOutput(chart)
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Saving')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Saving')
|
||||
await writeProcessFiles()
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Sleeping')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Sleeping')
|
||||
} else {
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Waiting for Data Mining to be up to date. No candles found at.')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Waiting for Data Mining to be up to date. No candles found at.')
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
@@ -159,7 +159,7 @@ exports.newTrainingProcess = function newTrainingProcess(bot, logger, UTILITIES)
|
||||
} else {
|
||||
/* We are processing Daily Files */
|
||||
do {
|
||||
global.EMIT_SESSION_STATUS(bot.SESSION_STATUS, bot.sessionKey)
|
||||
global.EMIT_SESSION_STATUS(bot.TRADING_SESSION_STATUS, bot.TRADING_SESSIONKey)
|
||||
/*
|
||||
We update the Trading Process Date with the date calculated at the simulation.
|
||||
We will use this date to load indicator and output files. After that we will
|
||||
@@ -171,9 +171,9 @@ exports.newTrainingProcess = function newTrainingProcess(bot, logger, UTILITIES)
|
||||
if (checkStopTaskGracefully() === false) { break }
|
||||
if (checkStopProcessing() === false) { break }
|
||||
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Waking up')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Waking up')
|
||||
if (await processDailyFiles() === false) {
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Waiting for Data Mining to be run')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Waiting for Data Mining to be run')
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
@@ -186,13 +186,13 @@ exports.newTrainingProcess = function newTrainingProcess(bot, logger, UTILITIES)
|
||||
The process of generating the output includes the trading simulation.
|
||||
*/
|
||||
if (checkThereAreCandles(chart) === true) {
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Running')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Running')
|
||||
await generateOutput(chart)
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Saving')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Saving')
|
||||
await writeProcessFiles()
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Sleeping')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Sleeping')
|
||||
} else {
|
||||
bot.sessionHeartBeat(undefined, undefined, 'Waiting for Data Mining to be up to date')
|
||||
bot.TRADING_SESSIONHeartBeat(undefined, undefined, 'Waiting for Data Mining to be up to date')
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE)
|
||||
return
|
||||
}
|
||||
@@ -219,7 +219,7 @@ exports.newTrainingProcess = function newTrainingProcess(bot, logger, UTILITIES)
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE)
|
||||
|
||||
function checkThereAreCandles(chart) {
|
||||
let sessionParameters = bot.SESSION.parameters
|
||||
let sessionParameters = bot.TRADING_SESSION.parameters
|
||||
let propertyName = 'at' + sessionParameters.timeFrame.config.label.replace('-', '')
|
||||
let candles = chart[propertyName].candles
|
||||
|
||||
@@ -236,7 +236,7 @@ exports.newTrainingProcess = function newTrainingProcess(bot, logger, UTILITIES)
|
||||
let statusReport;
|
||||
|
||||
/* We are going to use the start date as beging of market date. */
|
||||
contextVariables.dateBeginOfMarket = global.REMOVE_TIME(bot.SESSION.parameters.timeRange.config.initialDatetime)
|
||||
contextVariables.dateBeginOfMarket = global.REMOVE_TIME(bot.TRADING_SESSION.parameters.timeRange.config.initialDatetime)
|
||||
/*
|
||||
Here we get the status report from the bot who knows which is the end of the market.
|
||||
*/
|
||||
@@ -371,7 +371,7 @@ exports.newTrainingProcess = function newTrainingProcess(bot, logger, UTILITIES)
|
||||
|
||||
dataFiles = new Map();
|
||||
|
||||
if (bot.SESSION.parameters.timeFrame.config.label === timeFrameLabel) {
|
||||
if (bot.TRADING_SESSION.parameters.timeFrame.config.label === timeFrameLabel) {
|
||||
currentTimeFrame = global.marketFilesPeriods[n][0];
|
||||
currentTimeFrameLabel = global.marketFilesPeriods[n][1];
|
||||
}
|
||||
@@ -384,7 +384,7 @@ exports.newTrainingProcess = function newTrainingProcess(bot, logger, UTILITIES)
|
||||
}
|
||||
|
||||
if (dataDependenciesModule.isItADepenency(timeFrameLabel, datasetModule.node.parentNode.config.singularVariableName) !== true) {
|
||||
if (!(bot.SESSION.parameters.timeFrame.config.label === timeFrameLabel && datasetModule.node.parentNode.config.pluralVariableName === 'candles')) {
|
||||
if (!(bot.TRADING_SESSION.parameters.timeFrame.config.label === timeFrameLabel && datasetModule.node.parentNode.config.pluralVariableName === 'candles')) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -431,8 +431,8 @@ exports.newTrainingProcess = function newTrainingProcess(bot, logger, UTILITIES)
|
||||
let dataRecord = dataFile[i]
|
||||
let begin = dataRecord[beginIndex]
|
||||
let end = dataRecord[endIndex]
|
||||
if (end + timeFrame < bot.SESSION.parameters.timeRange.config.initialDatetime - 1) { continue } // /1 because we need the previous closed element
|
||||
if (begin > bot.SESSION.parameters.timeRange.config.finalDatetime) { continue }
|
||||
if (end + timeFrame < bot.TRADING_SESSION.parameters.timeRange.config.initialDatetime - 1) { continue } // /1 because we need the previous closed element
|
||||
if (begin > bot.TRADING_SESSION.parameters.timeRange.config.finalDatetime) { continue }
|
||||
result.push(dataRecord)
|
||||
}
|
||||
return result
|
||||
@@ -468,7 +468,7 @@ exports.newTrainingProcess = function newTrainingProcess(bot, logger, UTILITIES)
|
||||
}
|
||||
}
|
||||
|
||||
if (bot.SESSION.parameters.timeFrame.config.label === timeFrameLabel) {
|
||||
if (bot.TRADING_SESSION.parameters.timeFrame.config.label === timeFrameLabel) {
|
||||
currentTimeFrame = global.dailyFilePeriods[n][0];
|
||||
currentTimeFrameLabel = global.dailyFilePeriods[n][1];
|
||||
}
|
||||
@@ -488,7 +488,7 @@ exports.newTrainingProcess = function newTrainingProcess(bot, logger, UTILITIES)
|
||||
}
|
||||
|
||||
if (dataDependenciesModule.isItADepenency(timeFrameLabel, datasetModule.node.parentNode.config.singularVariableName) !== true) {
|
||||
if (!(bot.SESSION.parameters.timeFrame.config.label === timeFrameLabel && datasetModule.node.parentNode.config.pluralVariableName === 'candles')) {
|
||||
if (!(bot.TRADING_SESSION.parameters.timeFrame.config.label === timeFrameLabel && datasetModule.node.parentNode.config.pluralVariableName === 'candles')) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -653,7 +653,7 @@ exports.newTrainingProcess = function newTrainingProcess(bot, logger, UTILITIES)
|
||||
|
||||
let fileContent = JSON.stringify(dataRange);
|
||||
let fileName = '/Data.Range.json';
|
||||
let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + productCodeName + "/" + 'Multi-Period-Daily' + fileName;
|
||||
let filePath = bot.filePathRoot + "/Output/" + bot.TRADING_SESSION.folderName + "/" + productCodeName + "/" + 'Multi-Period-Daily' + fileName;
|
||||
|
||||
let response = await fileStorage.asyncCreateTextFile(filePath, fileContent + '\n')
|
||||
|
||||
@@ -692,7 +692,7 @@ exports.newTrainingProcess = function newTrainingProcess(bot, logger, UTILITIES)
|
||||
let fileContent = JSON.stringify(timeFramesArray)
|
||||
let fileName = '/Time.Frames.json';
|
||||
|
||||
let filePath = bot.filePathRoot + "/Output/" + bot.SESSION.folderName + "/" + productCodeName + "/" + processType + fileName;
|
||||
let filePath = bot.filePathRoot + "/Output/" + bot.TRADING_SESSION.folderName + "/" + productCodeName + "/" + processType + fileName;
|
||||
|
||||
let response = await fileStorage.asyncCreateTextFile(filePath, fileContent + '\n')
|
||||
if (response.err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
@@ -728,12 +728,12 @@ exports.newTrainingProcess = function newTrainingProcess(bot, logger, UTILITIES)
|
||||
|
||||
function checkIfSessionMustStop() {
|
||||
|
||||
if (bot.SESSION.type === 'Backtesting Session') {
|
||||
if (bot.TRADING_SESSION.type === 'Backtesting Session') {
|
||||
/*
|
||||
Backtests needs only one execution of this process to complete.
|
||||
*/
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[IMPORTANT] checkIfSessionMustStop -> Backtesting Session Finished. Stopping the Session now. ') }
|
||||
bot.SESSION.stop('Backtesting Session Finished.')
|
||||
bot.TRADING_SESSION.stop('Backtesting Session Finished.')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,6 +266,10 @@
|
||||
runTradingBot(botConfig, processConfig);
|
||||
break;
|
||||
}
|
||||
case 'AI Bot': {
|
||||
runAIBot(botConfig, processConfig);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
console.log(logDisplace + "Root : [ERROR] start -> bootingBot -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
|
||||
}
|
||||
@@ -296,6 +300,10 @@
|
||||
runTradingBot(botConfig, processConfig);
|
||||
break;
|
||||
}
|
||||
case 'AI Bot': {
|
||||
runAIBot(botConfig, processConfig);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
console.log(logDisplace + "Root : [ERROR] start -> bootingBot -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
|
||||
}
|
||||
@@ -339,6 +347,10 @@
|
||||
runTradingBot(botConfig, processConfig);
|
||||
break;
|
||||
}
|
||||
case 'AI Bot': {
|
||||
runAIBot(botConfig, processConfig);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
console.log(logDisplace + "Root : [ERROR] start -> bootingBot -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
|
||||
}
|
||||
@@ -540,6 +552,71 @@
|
||||
setTimeout(exitProcessInstance, WAIT_TIME_FOR_ALL_PROCESS_INSTANCES_TO_START)
|
||||
}
|
||||
}
|
||||
|
||||
function runAIBot(pBotConfig, pProcessConfig) {
|
||||
|
||||
global.TOTAL_PROCESS_INSTANCES_CREATED++
|
||||
|
||||
try {
|
||||
const DEBUG_MODULE = require(global.ROOT_DIR + 'DebugLog');
|
||||
let logger;
|
||||
|
||||
logger = DEBUG_MODULE.newDebugLog();
|
||||
global.LOGGER_MAP.set('runAIBot', logger)
|
||||
logger.bot = pBotConfig;
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> bootingBot -> runAIBot -> Entering function."); }
|
||||
|
||||
let aiBot = TRADING_BOT_MODULE.newAIBot(pBotConfig, logger);
|
||||
aiBot.initialize(pProcessConfig, onInitializeReady);
|
||||
|
||||
function onInitializeReady(err) {
|
||||
|
||||
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
|
||||
|
||||
aiBot.run(whenRunFinishes);
|
||||
|
||||
function whenRunFinishes(err) {
|
||||
|
||||
pBotConfig.loopCounter = 0;
|
||||
|
||||
let botId;
|
||||
|
||||
botId = pBotConfig.dataMine + "." + pBotConfig.codeName + "." + pBotConfig.process;
|
||||
|
||||
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
|
||||
|
||||
logger.write(MODULE_NAME, "[INFO] start -> bootingBot -> runAIBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished sucessfully.");
|
||||
logger.write(MODULE_NAME, "[INFO] start -> bootingBot -> runAIBot -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId);
|
||||
|
||||
logger.persist();
|
||||
|
||||
} else {
|
||||
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> bootingBot -> runAIBot -> onInitializeReady -> whenStartFinishes -> err = " + err.message);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> bootingBot -> runAIBot -> onInitializeReady -> whenStartFinishes -> Execution will be stopped. ");
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> bootingBot -> runAIBot -> onInitializeReady -> whenStartFinishes -> Bye.");
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> bootingBot -> runAIBot -> onInitializeReady -> whenStartFinishes -> Bot Id = " + botId);
|
||||
console.log(logDisplace + "Root : [ERROR] start -> bootingBot -> runAIBot -> onInitializeReady -> whenStartFinishes -> Bot execution finished with errors. Please check the logs.");
|
||||
logger.persist();
|
||||
}
|
||||
setTimeout(exitProcessInstance, WAIT_TIME_FOR_ALL_PROCESS_INSTANCES_TO_START)
|
||||
}
|
||||
|
||||
} else {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> bootingBot -> runAIBot -> onInitializeReady -> err = " + err.message);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> bootingBot -> runAIBot -> onInitializeReady -> Failed to initialize the bot. ");
|
||||
console.log(logDisplace + "Root : [ERROR] start -> bootingBot -> runAIBot -> onInitializeReady -> err = " + err.message);
|
||||
logger.persist();
|
||||
setTimeout(exitProcessInstance, WAIT_TIME_FOR_ALL_PROCESS_INSTANCES_TO_START)
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.log(logDisplace + "Root : [ERROR] start -> bootingBot -> runAIBot -> err = " + err.stack);
|
||||
setTimeout(exitProcessInstance, WAIT_TIME_FOR_ALL_PROCESS_INSTANCES_TO_START)
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
console.log(logDisplace + "Root : [ERROR] start -> bootingBot -> err = " + err.stack);
|
||||
|
||||
+16
-16
@@ -13,10 +13,10 @@ exports.newSocialBots = function newSocialBots(bot, logger) {
|
||||
return thisObject
|
||||
|
||||
function initialize() {
|
||||
if (bot.SESSION.socialBots !== undefined) {
|
||||
if (bot.SESSION.socialBots.bots !== undefined) {
|
||||
for (let i = 0; i < bot.SESSION.socialBots.bots.length; i++) {
|
||||
let socialBot = bot.SESSION.socialBots.bots[i]
|
||||
if (bot.TRADING_SESSION.socialBots !== undefined) {
|
||||
if (bot.TRADING_SESSION.socialBots.bots !== undefined) {
|
||||
for (let i = 0; i < bot.TRADING_SESSION.socialBots.bots.length; i++) {
|
||||
let socialBot = bot.TRADING_SESSION.socialBots.bots[i]
|
||||
if (socialBot.type === "Telegram Bot") {
|
||||
let config = socialBot.config
|
||||
socialBot.botInstance = TELEGRAM_BOT_MODULE.newTelegramBot(bot, logger)
|
||||
@@ -26,9 +26,9 @@ exports.newSocialBots = function newSocialBots(bot, logger) {
|
||||
}
|
||||
|
||||
function announce(text) {
|
||||
if (bot.SESSION.socialBots.bots !== undefined) {
|
||||
for (let i = 0; i < bot.SESSION.socialBots.bots.length; i++) {
|
||||
let socialBot = bot.SESSION.socialBots.bots[i]
|
||||
if (bot.TRADING_SESSION.socialBots.bots !== undefined) {
|
||||
for (let i = 0; i < bot.TRADING_SESSION.socialBots.bots.length; i++) {
|
||||
let socialBot = bot.TRADING_SESSION.socialBots.bots[i]
|
||||
try {
|
||||
if (socialBot.type === "Telegram Bot") {
|
||||
socialBot.botInstance.telegramAPI.sendMessage(socialBot.botInstance.chatId, text).catch(err => logger.write(MODULE_NAME, "[WARN] initialize -> initializeSocialBots -> announce -> Telegram API error -> err = " + err))
|
||||
@@ -40,15 +40,15 @@ exports.newSocialBots = function newSocialBots(bot, logger) {
|
||||
}
|
||||
}
|
||||
|
||||
bot.SESSION.socialBots.announce = announce
|
||||
bot.TRADING_SESSION.socialBots.announce = announce
|
||||
}
|
||||
}
|
||||
|
||||
function finalize() {
|
||||
if (bot.SESSION.socialBots === undefined) { return }
|
||||
if (bot.SESSION.socialBots.bots !== undefined) {
|
||||
for (let i = 0; i < bot.SESSION.socialBots.bots.length; i++) {
|
||||
let socialBot = bot.SESSION.socialBots.bots[i]
|
||||
if (bot.TRADING_SESSION.socialBots === undefined) { return }
|
||||
if (bot.TRADING_SESSION.socialBots.bots !== undefined) {
|
||||
for (let i = 0; i < bot.TRADING_SESSION.socialBots.bots.length; i++) {
|
||||
let socialBot = bot.TRADING_SESSION.socialBots.bots[i]
|
||||
if (socialBot.type === "Telegram Bot") {
|
||||
socialBot.botInstance.finalize()
|
||||
}
|
||||
@@ -57,10 +57,10 @@ exports.newSocialBots = function newSocialBots(bot, logger) {
|
||||
}
|
||||
|
||||
function sendMessage(message) {
|
||||
if (bot.SESSION.socialBots !== undefined) {
|
||||
if (bot.SESSION.socialBots.bots !== undefined) {
|
||||
for (let i = 0; i < bot.SESSION.socialBots.bots.length; i++) {
|
||||
let socialBot = bot.SESSION.socialBots.bots[i]
|
||||
if (bot.TRADING_SESSION.socialBots !== undefined) {
|
||||
if (bot.TRADING_SESSION.socialBots.bots !== undefined) {
|
||||
for (let i = 0; i < bot.TRADING_SESSION.socialBots.bots.length; i++) {
|
||||
let socialBot = bot.TRADING_SESSION.socialBots.bots[i]
|
||||
if (socialBot.type === "Telegram Bot") {
|
||||
socialBot.botInstance.sendMessage(message)
|
||||
}
|
||||
|
||||
+7
-3
@@ -100,8 +100,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (bot.SESSION !== undefined && statusDependencyNode.bottype === "Trading Bot") {
|
||||
sessionPath = bot.SESSION.folderName + "/"
|
||||
if (bot.TRADING_SESSION !== undefined && statusDependencyNode.bottype === "Trading Bot") {
|
||||
sessionPath = bot.TRADING_SESSION.folderName + "/"
|
||||
}
|
||||
|
||||
if (bot.AI_SESSION !== undefined && statusDependencyNode.bottype === "AI Bot") {
|
||||
sessionPath = bot.AI_SESSION.folderName + "/"
|
||||
}
|
||||
|
||||
/* Now we will see where do we need to fetch this status report from. */
|
||||
@@ -264,7 +268,7 @@
|
||||
On the contraty, if we are running a Sensor bot or an Indicator bot, we might, if necesary, use a previous version of a Status Report since
|
||||
there will be no big impact, just some reprocessing.
|
||||
*/
|
||||
if (bot.SESSION !== undefined) {
|
||||
if (bot.TRADING_SESSION !== undefined || bot.AI_SESSION !== undefined) {
|
||||
canUserPrevious = false
|
||||
} else {
|
||||
canUserPrevious = true
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ exports.newTelegramBot = function newTelegramBot(bot, logger) {
|
||||
thisObject.telegramBot = new Telegraf(botToken)
|
||||
thisObject.telegramBot.start((ctx) => ctx.reply('Hi! I am the Telegram Bot that will tell you what happens with your trading session.'))
|
||||
thisObject.telegramBot.help((ctx) => ctx.reply('I can stop the session if you type STOP.'))
|
||||
thisObject.telegramBot.hears('STOP', (ctx) => bot.SESSION.stop(' by STOP command at Telegram.'))
|
||||
thisObject.telegramBot.hears('STOP', (ctx) => bot.TRADING_SESSION.stop(' by STOP command at Telegram.'))
|
||||
thisObject.telegramBot.launch()
|
||||
|
||||
const Telegram = require('telegraf/telegram')
|
||||
|
||||
+13
-13
@@ -93,15 +93,15 @@
|
||||
+ " Main Loop # " + pad(Number(bot.loopCounter), 8) + " " + bot.processNode.session.type + " " + bot.processNode.session.name)
|
||||
|
||||
/* Checking if we need to need to emit any event */
|
||||
if (bot.SESSION_STATUS === 'Idle' && bot.STOP_SESSION === false) {
|
||||
bot.SESSION_STATUS = 'Running'
|
||||
if (bot.TRADING_SESSION_STATUS === 'Idle' && bot.STOP_SESSION === false) {
|
||||
bot.TRADING_SESSION_STATUS = 'Running'
|
||||
}
|
||||
|
||||
if (bot.SESSION_STATUS === 'Running' && bot.STOP_SESSION === true) {
|
||||
bot.SESSION_STATUS = 'Stopped'
|
||||
if (bot.TRADING_SESSION_STATUS === 'Running' && bot.STOP_SESSION === true) {
|
||||
bot.TRADING_SESSION_STATUS = 'Stopped'
|
||||
}
|
||||
|
||||
global.EMIT_SESSION_STATUS (bot.SESSION_STATUS, bot.sessionKey)
|
||||
global.EMIT_SESSION_STATUS (bot.TRADING_SESSION_STATUS, bot.TRADING_SESSIONKey)
|
||||
|
||||
/* Checking if we should process this loop or not.*/
|
||||
if (bot.STOP_SESSION === true) {
|
||||
@@ -534,7 +534,7 @@
|
||||
logger.persist();
|
||||
}
|
||||
|
||||
global.EVENT_SERVER_CLIENT.raiseEvent(bot.sessionKey, 'Stopped')
|
||||
global.EVENT_SERVER_CLIENT.raiseEvent(bot.TRADING_SESSIONKey, 'Stopped')
|
||||
processStopped()
|
||||
return;
|
||||
}
|
||||
@@ -560,17 +560,17 @@
|
||||
if (processConfig.waitsForExecutionFinishedEvent === true) {
|
||||
waitTime = 0
|
||||
} else {
|
||||
switch (bot.SESSION.type) {
|
||||
switch (bot.TRADING_SESSION.type) {
|
||||
case 'Live Trading Session': {
|
||||
waitTime = bot.SESSION.parameters.timeFrame.config.value
|
||||
waitTime = bot.TRADING_SESSION.parameters.timeFrame.config.value
|
||||
break
|
||||
}
|
||||
case 'Fordward Tessting Session': {
|
||||
waitTime = bot.SESSION.parameters.timeFrame.config.value
|
||||
waitTime = bot.TRADING_SESSION.parameters.timeFrame.config.value
|
||||
break
|
||||
}
|
||||
case 'Paper Trading Session': {
|
||||
waitTime = bot.SESSION.parameters.timeFrame.config.value
|
||||
waitTime = bot.TRADING_SESSION.parameters.timeFrame.config.value
|
||||
break
|
||||
}
|
||||
case 'Backtesting Session': {
|
||||
@@ -669,9 +669,9 @@
|
||||
}
|
||||
|
||||
function sessionStopped() {
|
||||
if (bot.SESSION_STATUS === 'Running') {
|
||||
global.EVENT_SERVER_CLIENT.raiseEvent(bot.sessionKey, 'Stopped')
|
||||
bot.SESSION_STATUS = 'Stopped'
|
||||
if (bot.TRADING_SESSION_STATUS === 'Running') {
|
||||
global.EVENT_SERVER_CLIENT.raiseEvent(bot.TRADING_SESSIONKey, 'Stopped')
|
||||
bot.TRADING_SESSION_STATUS = 'Stopped'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+94
-94
@@ -15,16 +15,16 @@
|
||||
function initialize(pProcessConfig, callBackFunction) {
|
||||
try {
|
||||
/* Initialize this info so that everything is logged propeerly */
|
||||
bot.SESSION = {
|
||||
bot.TRADING_SESSION = {
|
||||
name: bot.processNode.session.name,
|
||||
id: bot.processNode.session.id
|
||||
}
|
||||
|
||||
/* Set the folderName for early logging */
|
||||
if (bot.processNode.session.config.folderName === undefined) {
|
||||
bot.SESSION.folderName = bot.processNode.session.type.replace(' ', '-').replace(' ', '-') + '-' + bot.SESSION.id
|
||||
bot.TRADING_SESSION.folderName = bot.processNode.session.type.replace(' ', '-').replace(' ', '-') + '-' + bot.TRADING_SESSION.id
|
||||
} else {
|
||||
bot.SESSION.folderName = bot.processNode.session.type.replace(' ', '-').replace(' ', '-') + '-' + bot.processNode.session.config.folderName
|
||||
bot.TRADING_SESSION.folderName = bot.processNode.session.type.replace(' ', '-').replace(' ', '-') + '-' + bot.processNode.session.config.folderName
|
||||
}
|
||||
|
||||
/* Check if there is a session */
|
||||
@@ -35,43 +35,43 @@
|
||||
}
|
||||
|
||||
/* Listen to event to start or stop the session. */
|
||||
bot.sessionKey = bot.processNode.session.name + '-' + bot.processNode.session.type + '-' + bot.processNode.session.id
|
||||
global.SESSION_MAP.set(bot.sessionKey, bot.sessionKey)
|
||||
bot.TRADING_SESSIONKey = bot.processNode.session.name + '-' + bot.processNode.session.type + '-' + bot.processNode.session.id
|
||||
global.SESSION_MAP.set(bot.TRADING_SESSIONKey, bot.TRADING_SESSIONKey)
|
||||
|
||||
global.EVENT_SERVER_CLIENT.listenToEvent(bot.sessionKey, 'Session Status', undefined, bot.sessionKey, undefined, onSessionStatus)
|
||||
global.EVENT_SERVER_CLIENT.listenToEvent(bot.sessionKey, 'Run Session', undefined, bot.sessionKey, undefined, onSessionRun)
|
||||
global.EVENT_SERVER_CLIENT.listenToEvent(bot.sessionKey, 'Stop Session', undefined, bot.sessionKey, undefined, onSessionStop)
|
||||
global.EVENT_SERVER_CLIENT.listenToEvent(bot.sessionKey, 'Resume Session', undefined, bot.sessionKey, undefined, onSessionResume)
|
||||
global.EVENT_SERVER_CLIENT.listenToEvent(bot.TRADING_SESSIONKey, 'Session Status', undefined, bot.TRADING_SESSIONKey, undefined, onSessionStatus)
|
||||
global.EVENT_SERVER_CLIENT.listenToEvent(bot.TRADING_SESSIONKey, 'Run Session', undefined, bot.TRADING_SESSIONKey, undefined, onSessionRun)
|
||||
global.EVENT_SERVER_CLIENT.listenToEvent(bot.TRADING_SESSIONKey, 'Stop Session', undefined, bot.TRADING_SESSIONKey, undefined, onSessionStop)
|
||||
global.EVENT_SERVER_CLIENT.listenToEvent(bot.TRADING_SESSIONKey, 'Resume Session', undefined, bot.TRADING_SESSIONKey, undefined, onSessionResume)
|
||||
|
||||
/* Connect this here so that it is accesible from other places */
|
||||
bot.sessionError = sessionError
|
||||
bot.sessionWarning = sessionWarning
|
||||
bot.sessionInfo = sessionInfo
|
||||
bot.TRADING_SESSIONError = sessionError
|
||||
bot.TRADING_SESSIONWarning = sessionWarning
|
||||
bot.TRADING_SESSIONInfo = sessionInfo
|
||||
|
||||
/* Heartbeats sent to the UI */
|
||||
bot.sessionHeartBeat = sessionHeartBeat
|
||||
bot.TRADING_SESSIONHeartBeat = sessionHeartBeat
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE)
|
||||
return
|
||||
|
||||
function onSessionStatus() {
|
||||
if (bot.SESSION_STATUS === 'Running') {
|
||||
if (bot.TRADING_SESSION_STATUS === 'Running') {
|
||||
let event = {
|
||||
status: 'Session Runnning'
|
||||
}
|
||||
global.EVENT_SERVER_CLIENT.raiseEvent(bot.sessionKey, 'Status Response', event)
|
||||
global.EVENT_SERVER_CLIENT.raiseEvent(bot.TRADING_SESSIONKey, 'Status Response', event)
|
||||
} else {
|
||||
let event = {
|
||||
status: 'Not Session Runnning'
|
||||
}
|
||||
global.EVENT_SERVER_CLIENT.raiseEvent(bot.sessionKey, 'Status Response', event)
|
||||
global.EVENT_SERVER_CLIENT.raiseEvent(bot.TRADING_SESSIONKey, 'Status Response', event)
|
||||
}
|
||||
}
|
||||
|
||||
function onSessionRun(message) {
|
||||
try {
|
||||
/* This happens when the UI is reloaded, the session was running and tries to run it again. */
|
||||
if (bot.SESSION_STATUS === 'Idle' || bot.SESSION_STATUS === 'Running') {
|
||||
if (bot.TRADING_SESSION_STATUS === 'Idle' || bot.TRADING_SESSION_STATUS === 'Running') {
|
||||
parentLogger.write(MODULE_NAME, "[WARN] onSessionRun -> Event received to run the Session while it was already running. ")
|
||||
return
|
||||
}
|
||||
@@ -79,11 +79,11 @@
|
||||
/* We are going to run the Definition comming at the event. */
|
||||
bot.TRADING_SYSTEM = JSON.parse(message.event.tradingSystem)
|
||||
bot.TRADING_ENGINE = JSON.parse(message.event.tradingEngine)
|
||||
bot.SESSION = JSON.parse(message.event.session)
|
||||
bot.TRADING_SESSION = JSON.parse(message.event.session)
|
||||
bot.DEPENDENCY_FILTER = JSON.parse(message.event.dependencyFilter)
|
||||
bot.RESUME = false
|
||||
bot.FIRST_EXECUTION = true
|
||||
bot.SESSION.stop = stopSession // stop function
|
||||
bot.TRADING_SESSION.stop = stopSession // stop function
|
||||
|
||||
setUpSessionFolderName()
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
socialBotsModule.initialize()
|
||||
|
||||
let allGood
|
||||
switch (bot.SESSION.type) {
|
||||
switch (bot.TRADING_SESSION.type) {
|
||||
case 'Backtesting Session': {
|
||||
allGood = startBackTesting(message)
|
||||
break
|
||||
@@ -112,14 +112,14 @@
|
||||
}
|
||||
}
|
||||
if (allGood === true) {
|
||||
bot.SESSION_STATUS = 'Idle'
|
||||
bot.TRADING_SESSION_STATUS = 'Idle'
|
||||
bot.STOP_SESSION = false
|
||||
} else {
|
||||
bot.STOP_SESSION = true
|
||||
if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, '[IMPORTANT] onSessionRun -> Stopping the Session now. ') }
|
||||
}
|
||||
|
||||
socialBotsModule.sendMessage(bot.SESSION.type + " '" + bot.SESSION.name + "' is starting.")
|
||||
socialBotsModule.sendMessage(bot.TRADING_SESSION.type + " '" + bot.TRADING_SESSION.name + "' is starting.")
|
||||
} catch (err) {
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onSessionRun -> err = " + err.stack);
|
||||
}
|
||||
@@ -131,13 +131,13 @@
|
||||
|
||||
function onSessionResume(message) {
|
||||
try {
|
||||
if (bot.SESSION.stop === undefined) {
|
||||
if (bot.TRADING_SESSION.stop === undefined) {
|
||||
parentLogger.write(MODULE_NAME, "[WARN] onSessionResume -> Event received to resume the Session that have never be ran before. ")
|
||||
return
|
||||
}
|
||||
|
||||
/* This happens when the UI is reloaded, the session was running and tries to run it again. */
|
||||
if (bot.SESSION_STATUS === 'Idle' || bot.SESSION_STATUS === 'Running') {
|
||||
if (bot.TRADING_SESSION_STATUS === 'Idle' || bot.TRADING_SESSION_STATUS === 'Running') {
|
||||
parentLogger.write(MODULE_NAME, "[WARN] onSessionResume -> Event received to resume the Session while it was already running. ")
|
||||
return
|
||||
}
|
||||
@@ -145,7 +145,7 @@
|
||||
bot.RESUME = true
|
||||
bot.STOP_SESSION = false
|
||||
|
||||
socialBotsModule.sendMessage(bot.SESSION.type + " '" + bot.SESSION.name + "' is resuming.")
|
||||
socialBotsModule.sendMessage(bot.TRADING_SESSION.type + " '" + bot.TRADING_SESSION.name + "' is resuming.")
|
||||
} catch (err) {
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onSessionResume -> err = " + err.stack);
|
||||
}
|
||||
@@ -153,11 +153,11 @@
|
||||
|
||||
function stopSession(commandOrigin) {
|
||||
|
||||
socialBotsModule.sendMessage(bot.SESSION.type + " '" + bot.SESSION.name + "' is stopping " + commandOrigin)
|
||||
socialBotsModule.sendMessage(bot.TRADING_SESSION.type + " '" + bot.TRADING_SESSION.name + "' is stopping " + commandOrigin)
|
||||
socialBotsModule.finalize()
|
||||
bot.STOP_SESSION = true
|
||||
if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, '[IMPORTANT] stopSession -> Stopping the Session now. ') }
|
||||
sessionInfo(bot.SESSION, commandOrigin)
|
||||
sessionInfo(bot.TRADING_SESSION, commandOrigin)
|
||||
}
|
||||
|
||||
function setUpSessionFolderName() {
|
||||
@@ -167,12 +167,12 @@
|
||||
Set the folderName for logging, reports, context and data output
|
||||
*/
|
||||
let config
|
||||
if (bot.SESSION.config !== undefined) {
|
||||
config = bot.SESSION.config
|
||||
if (bot.TRADING_SESSION.config !== undefined) {
|
||||
config = bot.TRADING_SESSION.config
|
||||
if (config.folderName === undefined) {
|
||||
bot.SESSION.folderName = bot.processNode.session.type.replace(' ', '-').replace(' ', '-') + '-' + bot.SESSION.id
|
||||
bot.TRADING_SESSION.folderName = bot.processNode.session.type.replace(' ', '-').replace(' ', '-') + '-' + bot.TRADING_SESSION.id
|
||||
} else {
|
||||
bot.SESSION.folderName = bot.processNode.session.type.replace(' ', '-').replace(' ', '-') + '-' + bot.processNode.session.config.folderName
|
||||
bot.TRADING_SESSION.folderName = bot.processNode.session.type.replace(' ', '-').replace(' ', '-') + '-' + bot.processNode.session.config.folderName
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -183,16 +183,16 @@
|
||||
non critical is missing, we complete it with a default value.
|
||||
*/
|
||||
|
||||
if (bot.SESSION.parameters === undefined) {
|
||||
if (bot.TRADING_SESSION.parameters === undefined) {
|
||||
let errorMessage = "Session Node with no Parameters."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION, errorMessage)
|
||||
bot.TRADING_SESSIONError(bot.TRADING_SESSION, errorMessage)
|
||||
return false
|
||||
}
|
||||
|
||||
/* Time Range */
|
||||
if (bot.SESSION.parameters.timeRange === undefined) { // if the Time Range is missing we create a default one.
|
||||
bot.SESSION.parameters.timeRange = {
|
||||
if (bot.TRADING_SESSION.parameters.timeRange === undefined) { // if the Time Range is missing we create a default one.
|
||||
bot.TRADING_SESSION.parameters.timeRange = {
|
||||
name: 'Missing Time Range',
|
||||
type: 'Time Range',
|
||||
config: {
|
||||
@@ -202,18 +202,18 @@
|
||||
}
|
||||
} else {
|
||||
/* Check that we received valid dates */
|
||||
if (bot.SESSION.type === 'Backtesting Session') {
|
||||
if (isNaN(new Date(bot.SESSION.parameters.timeRange.config.initialDatetime)).valueOf()) {
|
||||
if (bot.TRADING_SESSION.type === 'Backtesting Session') {
|
||||
if (isNaN(new Date(bot.TRADING_SESSION.parameters.timeRange.config.initialDatetime)).valueOf()) {
|
||||
let errorMessage = "sessionParameters.timeRange.config.initialDatetime is not a valid date."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION.parameters, errorMessage)
|
||||
bot.TRADING_SESSIONError(bot.TRADING_SESSION.parameters, errorMessage)
|
||||
return false
|
||||
}
|
||||
}
|
||||
if (isNaN(new Date(bot.SESSION.parameters.timeRange.config.finalDatetime)).valueOf()) {
|
||||
if (isNaN(new Date(bot.TRADING_SESSION.parameters.timeRange.config.finalDatetime)).valueOf()) {
|
||||
let errorMessage = "sessionParameters.timeRange.config.initialDatetime is not a valid date."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION.parameters, errorMessage)
|
||||
bot.TRADING_SESSIONError(bot.TRADING_SESSION.parameters, errorMessage)
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -222,7 +222,7 @@
|
||||
let today = (new Date()).valueOf()
|
||||
let aYearAgo = today - global.ONE_YEAR_IN_MILISECONDS
|
||||
let aYearFromNow = today + global.ONE_YEAR_IN_MILISECONDS
|
||||
switch (bot.SESSION.type) {
|
||||
switch (bot.TRADING_SESSION.type) {
|
||||
case 'Backtesting Session': {
|
||||
useDefaultDatetimes(aYearAgo, today)
|
||||
break
|
||||
@@ -248,81 +248,81 @@
|
||||
*/
|
||||
|
||||
/* Initial Datetime */
|
||||
if (bot.SESSION.type === 'Backtesting Session') {
|
||||
if (bot.SESSION.parameters.timeRange.config.initialDatetime === undefined) {
|
||||
bot.SESSION.parameters.timeRange.config.initialDatetime = initialDefault
|
||||
if (bot.TRADING_SESSION.type === 'Backtesting Session') {
|
||||
if (bot.TRADING_SESSION.parameters.timeRange.config.initialDatetime === undefined) {
|
||||
bot.TRADING_SESSION.parameters.timeRange.config.initialDatetime = initialDefault
|
||||
} else {
|
||||
bot.SESSION.parameters.timeRange.config.initialDatetime = (new Date(bot.SESSION.parameters.timeRange.config.initialDatetime)).valueOf()
|
||||
bot.TRADING_SESSION.parameters.timeRange.config.initialDatetime = (new Date(bot.TRADING_SESSION.parameters.timeRange.config.initialDatetime)).valueOf()
|
||||
}
|
||||
} else {
|
||||
/* Non backtest session can start from the past only if explicitly configured that way */
|
||||
if (bot.SESSION.parameters.timeRange.config.initialDatetime === undefined || bot.SESSION.parameters.timeRange.config.allowStartingFromThePast !== true) {
|
||||
bot.SESSION.parameters.timeRange.config.initialDatetime = initialDefault
|
||||
if (bot.TRADING_SESSION.parameters.timeRange.config.initialDatetime === undefined || bot.TRADING_SESSION.parameters.timeRange.config.allowStartingFromThePast !== true) {
|
||||
bot.TRADING_SESSION.parameters.timeRange.config.initialDatetime = initialDefault
|
||||
} else {
|
||||
bot.SESSION.parameters.timeRange.config.initialDatetime = (new Date(bot.SESSION.parameters.timeRange.config.initialDatetime)).valueOf()
|
||||
bot.TRADING_SESSION.parameters.timeRange.config.initialDatetime = (new Date(bot.TRADING_SESSION.parameters.timeRange.config.initialDatetime)).valueOf()
|
||||
}
|
||||
}
|
||||
|
||||
/* Final Datetime */
|
||||
if (bot.SESSION.parameters.timeRange.config.finalDatetime === undefined) {
|
||||
bot.SESSION.parameters.timeRange.config.finalDatetime = finalDefault
|
||||
if (bot.TRADING_SESSION.parameters.timeRange.config.finalDatetime === undefined) {
|
||||
bot.TRADING_SESSION.parameters.timeRange.config.finalDatetime = finalDefault
|
||||
} else {
|
||||
bot.SESSION.parameters.timeRange.config.finalDatetime = (new Date(bot.SESSION.parameters.timeRange.config.finalDatetime)).valueOf()
|
||||
bot.TRADING_SESSION.parameters.timeRange.config.finalDatetime = (new Date(bot.TRADING_SESSION.parameters.timeRange.config.finalDatetime)).valueOf()
|
||||
}
|
||||
}
|
||||
|
||||
/* Time Frame */
|
||||
if (bot.SESSION.parameters.timeFrame === undefined) {
|
||||
if (bot.TRADING_SESSION.parameters.timeFrame === undefined) {
|
||||
let errorMessage = "Session Parameters Node with no Time Frame."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION.parameters, errorMessage)
|
||||
bot.TRADING_SESSIONError(bot.TRADING_SESSION.parameters, errorMessage)
|
||||
return false
|
||||
}
|
||||
if (bot.SESSION.parameters.timeFrame.config.label === undefined) {
|
||||
if (bot.TRADING_SESSION.parameters.timeFrame.config.label === undefined) {
|
||||
let errorMessage = "Session Parameters Node with no Time Frame Label configuration."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION.parameters.timeFrame, errorMessage)
|
||||
bot.TRADING_SESSIONError(bot.TRADING_SESSION.parameters.timeFrame, errorMessage)
|
||||
return false
|
||||
}
|
||||
bot.SESSION.parameters.timeFrame.config.value = getTimeFrameFromLabel(bot.SESSION.parameters.timeFrame.config.label)
|
||||
if (bot.SESSION.parameters.timeFrame.config.value === undefined) {
|
||||
bot.TRADING_SESSION.parameters.timeFrame.config.value = getTimeFrameFromLabel(bot.TRADING_SESSION.parameters.timeFrame.config.label)
|
||||
if (bot.TRADING_SESSION.parameters.timeFrame.config.value === undefined) {
|
||||
let errorMessage = "Config error: label value not recognized. Try 01-min or 01-hs for example."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION.parameters.timeFrame, errorMessage)
|
||||
bot.TRADING_SESSIONError(bot.TRADING_SESSION.parameters.timeFrame, errorMessage)
|
||||
return false
|
||||
}
|
||||
|
||||
/* Session Base Asset */
|
||||
if (bot.SESSION.parameters.sessionBaseAsset === undefined) {
|
||||
if (bot.TRADING_SESSION.parameters.sessionBaseAsset === undefined) {
|
||||
let errorMessage = "Session Parameters Node with no Session Base Asset."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION.parameters, errorMessage)
|
||||
bot.TRADING_SESSIONError(bot.TRADING_SESSION.parameters, errorMessage)
|
||||
return false
|
||||
}
|
||||
if (bot.SESSION.parameters.sessionBaseAsset.config.initialBalance === undefined) {
|
||||
if (bot.TRADING_SESSION.parameters.sessionBaseAsset.config.initialBalance === undefined) {
|
||||
let errorMessage = "Session Parameters Session Base Asset with no initialBalance configuration."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION.parameters.sessionBaseAsset, errorMessage)
|
||||
bot.TRADING_SESSIONError(bot.TRADING_SESSION.parameters.sessionBaseAsset, errorMessage)
|
||||
return false
|
||||
}
|
||||
|
||||
/* Session Quoted Asset */
|
||||
if (bot.SESSION.parameters.sessionQuotedAsset === undefined) {
|
||||
if (bot.TRADING_SESSION.parameters.sessionQuotedAsset === undefined) {
|
||||
let errorMessage = "Session Parameters Node with no Session Quoted Asset."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION.parameters, errorMessage)
|
||||
bot.TRADING_SESSIONError(bot.TRADING_SESSION.parameters, errorMessage)
|
||||
return false
|
||||
}
|
||||
if (bot.SESSION.parameters.sessionQuotedAsset.config.initialBalance === undefined) {
|
||||
if (bot.TRADING_SESSION.parameters.sessionQuotedAsset.config.initialBalance === undefined) {
|
||||
let errorMessage = "Session Parameters Session Quoted Asset with no initialBalance configuration."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION.parameters.sessionQuotedAsset, errorMessage)
|
||||
bot.TRADING_SESSIONError(bot.TRADING_SESSION.parameters.sessionQuotedAsset, errorMessage)
|
||||
return false
|
||||
}
|
||||
|
||||
/* Slippage */
|
||||
if (bot.SESSION.parameters.slippage === undefined) { // if the Slippage is missing we create a default one.
|
||||
bot.SESSION.parameters.slippage = {
|
||||
if (bot.TRADING_SESSION.parameters.slippage === undefined) { // if the Slippage is missing we create a default one.
|
||||
bot.TRADING_SESSION.parameters.slippage = {
|
||||
name: 'Missing Slippage',
|
||||
type: 'Slippage',
|
||||
config: {
|
||||
@@ -332,19 +332,19 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bot.SESSION.parameters.slippage.config.marketOrderRate === undefined) { // if the marketOrderRate is missing we create a default one.
|
||||
bot.SESSION.parameters.slippage.config.marketOrderRate = 0
|
||||
if (bot.TRADING_SESSION.parameters.slippage.config.marketOrderRate === undefined) { // if the marketOrderRate is missing we create a default one.
|
||||
bot.TRADING_SESSION.parameters.slippage.config.marketOrderRate = 0
|
||||
}
|
||||
if (bot.SESSION.parameters.slippage.config.stopLoss === undefined) { // if the stopLoss is missing we create a default one.
|
||||
bot.SESSION.parameters.slippage.config.stopLoss = 0
|
||||
if (bot.TRADING_SESSION.parameters.slippage.config.stopLoss === undefined) { // if the stopLoss is missing we create a default one.
|
||||
bot.TRADING_SESSION.parameters.slippage.config.stopLoss = 0
|
||||
}
|
||||
if (bot.SESSION.parameters.slippage.config.takeProfit === undefined) { // if the takeProfit is missing we create a default one.
|
||||
bot.SESSION.parameters.slippage.config.takeProfit = 0
|
||||
if (bot.TRADING_SESSION.parameters.slippage.config.takeProfit === undefined) { // if the takeProfit is missing we create a default one.
|
||||
bot.TRADING_SESSION.parameters.slippage.config.takeProfit = 0
|
||||
}
|
||||
|
||||
/* Fee Structure */
|
||||
if (bot.SESSION.parameters.feeStructure === undefined) { // if the Fee Structure is missing we create a default one.
|
||||
bot.SESSION.parameters.feeStructure = {
|
||||
if (bot.TRADING_SESSION.parameters.feeStructure === undefined) { // if the Fee Structure is missing we create a default one.
|
||||
bot.TRADING_SESSION.parameters.feeStructure = {
|
||||
name: 'Missing Fee Structure',
|
||||
type: 'Fee Structure',
|
||||
config: {
|
||||
@@ -353,11 +353,11 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bot.SESSION.parameters.feeStructure.config.maker === undefined) { // if the maker is missing we create a default one.
|
||||
bot.SESSION.parameters.feeStructure.config.maker = 0
|
||||
if (bot.TRADING_SESSION.parameters.feeStructure.config.maker === undefined) { // if the maker is missing we create a default one.
|
||||
bot.TRADING_SESSION.parameters.feeStructure.config.maker = 0
|
||||
}
|
||||
if (bot.SESSION.parameters.feeStructure.config.taker === undefined) { // if the taker is missing we create a default one.
|
||||
bot.SESSION.parameters.feeStructure.config.taker = 0
|
||||
if (bot.TRADING_SESSION.parameters.feeStructure.config.taker === undefined) { // if the taker is missing we create a default one.
|
||||
bot.TRADING_SESSION.parameters.feeStructure.config.taker = 0
|
||||
}
|
||||
|
||||
return true
|
||||
@@ -371,7 +371,7 @@
|
||||
if (bot.KEY === undefined || bot.SECRET === undefined) {
|
||||
let errorMessage = "Key 'codeName' or 'secret' not provided. Plese check that and try again."
|
||||
if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, "[ERROR] initialize -> startLiveTrading -> " + errorMessage); }
|
||||
bot.sessionError(bot.SESSION, errorMessage)
|
||||
bot.TRADING_SESSIONError(bot.TRADING_SESSION, errorMessage)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -387,20 +387,20 @@
|
||||
/* Reduce the balance */
|
||||
let balancePercentage = 1 // This is the default value
|
||||
|
||||
if (bot.SESSION.config.balancePercentage !== undefined) {
|
||||
balancePercentage = bot.SESSION.config.balancePercentage
|
||||
if (bot.TRADING_SESSION.config.balancePercentage !== undefined) {
|
||||
balancePercentage = bot.TRADING_SESSION.config.balancePercentage
|
||||
}
|
||||
|
||||
bot.SESSION.parameters.sessionBaseAsset.config.initialBalance = bot.SESSION.parameters.sessionBaseAsset.config.initialBalance * balancePercentage / 100
|
||||
bot.SESSION.parameters.sessionQuotedAsset.config.initialBalance = bot.SESSION.parameters.sessionQuotedAsset.config.initialBalance * balancePercentage / 100
|
||||
bot.TRADING_SESSION.parameters.sessionBaseAsset.config.initialBalance = bot.TRADING_SESSION.parameters.sessionBaseAsset.config.initialBalance * balancePercentage / 100
|
||||
bot.TRADING_SESSION.parameters.sessionQuotedAsset.config.initialBalance = bot.TRADING_SESSION.parameters.sessionQuotedAsset.config.initialBalance * balancePercentage / 100
|
||||
|
||||
bot.SESSION.parameters.sessionBaseAsset.config.minimumBalance = bot.SESSION.parameters.sessionBaseAsset.config.minimumBalance * balancePercentage / 100
|
||||
bot.SESSION.parameters.sessionQuotedAsset.config.minimumBalance = bot.SESSION.parameters.sessionQuotedAsset.config.minimumBalance * balancePercentage / 100
|
||||
bot.TRADING_SESSION.parameters.sessionBaseAsset.config.minimumBalance = bot.TRADING_SESSION.parameters.sessionBaseAsset.config.minimumBalance * balancePercentage / 100
|
||||
bot.TRADING_SESSION.parameters.sessionQuotedAsset.config.minimumBalance = bot.TRADING_SESSION.parameters.sessionQuotedAsset.config.minimumBalance * balancePercentage / 100
|
||||
|
||||
bot.SESSION.parameters.sessionBaseAsset.config.maximumBalance = bot.SESSION.parameters.sessionBaseAsset.config.maximumBalance * balancePercentage / 100
|
||||
bot.SESSION.parameters.sessionQuotedAsset.config.maximumBalance = bot.SESSION.parameters.sessionQuotedAsset.config.maximumBalance * balancePercentage / 100
|
||||
bot.TRADING_SESSION.parameters.sessionBaseAsset.config.maximumBalance = bot.TRADING_SESSION.parameters.sessionBaseAsset.config.maximumBalance * balancePercentage / 100
|
||||
bot.TRADING_SESSION.parameters.sessionQuotedAsset.config.maximumBalance = bot.TRADING_SESSION.parameters.sessionQuotedAsset.config.maximumBalance * balancePercentage / 100
|
||||
|
||||
pProcessConfig.normalWaitTime = bot.SESSION.parameters.timeFrame.config.value
|
||||
pProcessConfig.normalWaitTime = bot.TRADING_SESSION.parameters.timeFrame.config.value
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -437,7 +437,7 @@
|
||||
percentage: percentage,
|
||||
status: status
|
||||
}
|
||||
global.EVENT_SERVER_CLIENT.raiseEvent(bot.sessionKey, 'Heartbeat', event)
|
||||
global.EVENT_SERVER_CLIENT.raiseEvent(bot.TRADING_SESSIONKey, 'Heartbeat', event)
|
||||
|
||||
if (global.STOP_TASK_GRACEFULLY === true) {
|
||||
bot.STOP_SESSION = true
|
||||
@@ -459,7 +459,7 @@
|
||||
errorMessage: errorMessage
|
||||
}
|
||||
}
|
||||
global.EVENT_SERVER_CLIENT.raiseEvent(bot.sessionKey, 'Error', event)
|
||||
global.EVENT_SERVER_CLIENT.raiseEvent(bot.TRADING_SESSIONKey, 'Error', event)
|
||||
|
||||
if (global.STOP_TASK_GRACEFULLY === true) {
|
||||
bot.STOP_SESSION = true
|
||||
@@ -481,7 +481,7 @@
|
||||
warningMessage: warningMessage
|
||||
}
|
||||
}
|
||||
global.EVENT_SERVER_CLIENT.raiseEvent(bot.sessionKey, 'Warning', event)
|
||||
global.EVENT_SERVER_CLIENT.raiseEvent(bot.TRADING_SESSIONKey, 'Warning', event)
|
||||
|
||||
if (global.STOP_TASK_GRACEFULLY === true) {
|
||||
bot.STOP_SESSION = true
|
||||
@@ -503,7 +503,7 @@
|
||||
infoMessage: infoMessage
|
||||
}
|
||||
}
|
||||
global.EVENT_SERVER_CLIENT.raiseEvent(bot.sessionKey, 'Info', event)
|
||||
global.EVENT_SERVER_CLIENT.raiseEvent(bot.TRADING_SESSIONKey, 'Info', event)
|
||||
|
||||
if (global.STOP_TASK_GRACEFULLY === true) {
|
||||
bot.STOP_SESSION = true
|
||||
|
||||
+74
-74
@@ -15,16 +15,16 @@ exports.newTrainingSession = function newTrainingSession(bot, parentLogger) {
|
||||
function initialize(pProcessConfig, callBackFunction) {
|
||||
try {
|
||||
/* Initialize this info so that everything is logged propeerly */
|
||||
bot.SESSION = {
|
||||
bot.AI_SESSION = {
|
||||
name: bot.processNode.session.name,
|
||||
id: bot.processNode.session.id
|
||||
}
|
||||
|
||||
/* Set the folderName for early logging */
|
||||
if (bot.processNode.session.config.folderName === undefined) {
|
||||
bot.SESSION.folderName = bot.processNode.session.type.replace(' ', '-').replace(' ', '-') + '-' + bot.SESSION.id
|
||||
bot.AI_SESSION.folderName = bot.processNode.session.type.replace(' ', '-').replace(' ', '-') + '-' + bot.AI_SESSION.id
|
||||
} else {
|
||||
bot.SESSION.folderName = bot.processNode.session.type.replace(' ', '-').replace(' ', '-') + '-' + bot.processNode.session.config.folderName
|
||||
bot.AI_SESSION.folderName = bot.processNode.session.type.replace(' ', '-').replace(' ', '-') + '-' + bot.processNode.session.config.folderName
|
||||
}
|
||||
|
||||
/* Check if there is a session */
|
||||
@@ -79,11 +79,11 @@ exports.newTrainingSession = function newTrainingSession(bot, parentLogger) {
|
||||
/* We are going to run the Definition comming at the event. */
|
||||
bot.TRADING_SYSTEM = JSON.parse(message.event.tradingSystem)
|
||||
bot.TRADING_ENGINE = JSON.parse(message.event.tradingEngine)
|
||||
bot.SESSION = JSON.parse(message.event.session)
|
||||
bot.AI_SESSION = JSON.parse(message.event.session)
|
||||
bot.DEPENDENCY_FILTER = JSON.parse(message.event.dependencyFilter)
|
||||
bot.RESUME = false
|
||||
bot.FIRST_EXECUTION = true
|
||||
bot.SESSION.stop = stopSession // stop function
|
||||
bot.AI_SESSION.stop = stopSession // stop function
|
||||
|
||||
setUpSessionFolderName()
|
||||
|
||||
@@ -93,7 +93,7 @@ exports.newTrainingSession = function newTrainingSession(bot, parentLogger) {
|
||||
socialBotsModule.initialize()
|
||||
|
||||
let allGood
|
||||
switch (bot.SESSION.type) {
|
||||
switch (bot.AI_SESSION.type) {
|
||||
case 'Backtesting Session': {
|
||||
allGood = startBackTesting(message)
|
||||
break
|
||||
@@ -119,7 +119,7 @@ exports.newTrainingSession = function newTrainingSession(bot, parentLogger) {
|
||||
if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, '[IMPORTANT] onSessionRun -> Stopping the Session now. ') }
|
||||
}
|
||||
|
||||
socialBotsModule.sendMessage(bot.SESSION.type + " '" + bot.SESSION.name + "' is starting.")
|
||||
socialBotsModule.sendMessage(bot.AI_SESSION.type + " '" + bot.AI_SESSION.name + "' is starting.")
|
||||
} catch (err) {
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onSessionRun -> err = " + err.stack);
|
||||
}
|
||||
@@ -131,7 +131,7 @@ exports.newTrainingSession = function newTrainingSession(bot, parentLogger) {
|
||||
|
||||
function onSessionResume(message) {
|
||||
try {
|
||||
if (bot.SESSION.stop === undefined) {
|
||||
if (bot.AI_SESSION.stop === undefined) {
|
||||
parentLogger.write(MODULE_NAME, "[WARN] onSessionResume -> Event received to resume the Session that have never be ran before. ")
|
||||
return
|
||||
}
|
||||
@@ -145,7 +145,7 @@ exports.newTrainingSession = function newTrainingSession(bot, parentLogger) {
|
||||
bot.RESUME = true
|
||||
bot.STOP_SESSION = false
|
||||
|
||||
socialBotsModule.sendMessage(bot.SESSION.type + " '" + bot.SESSION.name + "' is resuming.")
|
||||
socialBotsModule.sendMessage(bot.AI_SESSION.type + " '" + bot.AI_SESSION.name + "' is resuming.")
|
||||
} catch (err) {
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onSessionResume -> err = " + err.stack);
|
||||
}
|
||||
@@ -153,11 +153,11 @@ exports.newTrainingSession = function newTrainingSession(bot, parentLogger) {
|
||||
|
||||
function stopSession(commandOrigin) {
|
||||
|
||||
socialBotsModule.sendMessage(bot.SESSION.type + " '" + bot.SESSION.name + "' is stopping " + commandOrigin)
|
||||
socialBotsModule.sendMessage(bot.AI_SESSION.type + " '" + bot.AI_SESSION.name + "' is stopping " + commandOrigin)
|
||||
socialBotsModule.finalize()
|
||||
bot.STOP_SESSION = true
|
||||
if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, '[IMPORTANT] stopSession -> Stopping the Session now. ') }
|
||||
sessionInfo(bot.SESSION, commandOrigin)
|
||||
sessionInfo(bot.AI_SESSION, commandOrigin)
|
||||
}
|
||||
|
||||
function setUpSessionFolderName() {
|
||||
@@ -167,12 +167,12 @@ exports.newTrainingSession = function newTrainingSession(bot, parentLogger) {
|
||||
Set the folderName for logging, reports, context and data output
|
||||
*/
|
||||
let config
|
||||
if (bot.SESSION.config !== undefined) {
|
||||
config = bot.SESSION.config
|
||||
if (bot.AI_SESSION.config !== undefined) {
|
||||
config = bot.AI_SESSION.config
|
||||
if (config.folderName === undefined) {
|
||||
bot.SESSION.folderName = bot.processNode.session.type.replace(' ', '-').replace(' ', '-') + '-' + bot.SESSION.id
|
||||
bot.AI_SESSION.folderName = bot.processNode.session.type.replace(' ', '-').replace(' ', '-') + '-' + bot.AI_SESSION.id
|
||||
} else {
|
||||
bot.SESSION.folderName = bot.processNode.session.type.replace(' ', '-').replace(' ', '-') + '-' + bot.processNode.session.config.folderName
|
||||
bot.AI_SESSION.folderName = bot.processNode.session.type.replace(' ', '-').replace(' ', '-') + '-' + bot.processNode.session.config.folderName
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -183,16 +183,16 @@ exports.newTrainingSession = function newTrainingSession(bot, parentLogger) {
|
||||
non critical is missing, we complete it with a default value.
|
||||
*/
|
||||
|
||||
if (bot.SESSION.parameters === undefined) {
|
||||
if (bot.AI_SESSION.parameters === undefined) {
|
||||
let errorMessage = "Session Node with no Parameters."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION, errorMessage)
|
||||
bot.sessionError(bot.AI_SESSION, errorMessage)
|
||||
return false
|
||||
}
|
||||
|
||||
/* Time Range */
|
||||
if (bot.SESSION.parameters.timeRange === undefined) { // if the Time Range is missing we create a default one.
|
||||
bot.SESSION.parameters.timeRange = {
|
||||
if (bot.AI_SESSION.parameters.timeRange === undefined) { // if the Time Range is missing we create a default one.
|
||||
bot.AI_SESSION.parameters.timeRange = {
|
||||
name: 'Missing Time Range',
|
||||
type: 'Time Range',
|
||||
config: {
|
||||
@@ -202,18 +202,18 @@ exports.newTrainingSession = function newTrainingSession(bot, parentLogger) {
|
||||
}
|
||||
} else {
|
||||
/* Check that we received valid dates */
|
||||
if (bot.SESSION.type === 'Backtesting Session') {
|
||||
if (isNaN(new Date(bot.SESSION.parameters.timeRange.config.initialDatetime)).valueOf()) {
|
||||
if (bot.AI_SESSION.type === 'Backtesting Session') {
|
||||
if (isNaN(new Date(bot.AI_SESSION.parameters.timeRange.config.initialDatetime)).valueOf()) {
|
||||
let errorMessage = "sessionParameters.timeRange.config.initialDatetime is not a valid date."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION.parameters, errorMessage)
|
||||
bot.sessionError(bot.AI_SESSION.parameters, errorMessage)
|
||||
return false
|
||||
}
|
||||
}
|
||||
if (isNaN(new Date(bot.SESSION.parameters.timeRange.config.finalDatetime)).valueOf()) {
|
||||
if (isNaN(new Date(bot.AI_SESSION.parameters.timeRange.config.finalDatetime)).valueOf()) {
|
||||
let errorMessage = "sessionParameters.timeRange.config.initialDatetime is not a valid date."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION.parameters, errorMessage)
|
||||
bot.sessionError(bot.AI_SESSION.parameters, errorMessage)
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -222,7 +222,7 @@ exports.newTrainingSession = function newTrainingSession(bot, parentLogger) {
|
||||
let today = (new Date()).valueOf()
|
||||
let aYearAgo = today - global.ONE_YEAR_IN_MILISECONDS
|
||||
let aYearFromNow = today + global.ONE_YEAR_IN_MILISECONDS
|
||||
switch (bot.SESSION.type) {
|
||||
switch (bot.AI_SESSION.type) {
|
||||
case 'Backtesting Session': {
|
||||
useDefaultDatetimes(aYearAgo, today)
|
||||
break
|
||||
@@ -248,81 +248,81 @@ exports.newTrainingSession = function newTrainingSession(bot, parentLogger) {
|
||||
*/
|
||||
|
||||
/* Initial Datetime */
|
||||
if (bot.SESSION.type === 'Backtesting Session') {
|
||||
if (bot.SESSION.parameters.timeRange.config.initialDatetime === undefined) {
|
||||
bot.SESSION.parameters.timeRange.config.initialDatetime = initialDefault
|
||||
if (bot.AI_SESSION.type === 'Backtesting Session') {
|
||||
if (bot.AI_SESSION.parameters.timeRange.config.initialDatetime === undefined) {
|
||||
bot.AI_SESSION.parameters.timeRange.config.initialDatetime = initialDefault
|
||||
} else {
|
||||
bot.SESSION.parameters.timeRange.config.initialDatetime = (new Date(bot.SESSION.parameters.timeRange.config.initialDatetime)).valueOf()
|
||||
bot.AI_SESSION.parameters.timeRange.config.initialDatetime = (new Date(bot.AI_SESSION.parameters.timeRange.config.initialDatetime)).valueOf()
|
||||
}
|
||||
} else {
|
||||
/* Non backtest session can start from the past only if explicitly configured that way */
|
||||
if (bot.SESSION.parameters.timeRange.config.initialDatetime === undefined || bot.SESSION.parameters.timeRange.config.allowStartingFromThePast !== true) {
|
||||
bot.SESSION.parameters.timeRange.config.initialDatetime = initialDefault
|
||||
if (bot.AI_SESSION.parameters.timeRange.config.initialDatetime === undefined || bot.AI_SESSION.parameters.timeRange.config.allowStartingFromThePast !== true) {
|
||||
bot.AI_SESSION.parameters.timeRange.config.initialDatetime = initialDefault
|
||||
} else {
|
||||
bot.SESSION.parameters.timeRange.config.initialDatetime = (new Date(bot.SESSION.parameters.timeRange.config.initialDatetime)).valueOf()
|
||||
bot.AI_SESSION.parameters.timeRange.config.initialDatetime = (new Date(bot.AI_SESSION.parameters.timeRange.config.initialDatetime)).valueOf()
|
||||
}
|
||||
}
|
||||
|
||||
/* Final Datetime */
|
||||
if (bot.SESSION.parameters.timeRange.config.finalDatetime === undefined) {
|
||||
bot.SESSION.parameters.timeRange.config.finalDatetime = finalDefault
|
||||
if (bot.AI_SESSION.parameters.timeRange.config.finalDatetime === undefined) {
|
||||
bot.AI_SESSION.parameters.timeRange.config.finalDatetime = finalDefault
|
||||
} else {
|
||||
bot.SESSION.parameters.timeRange.config.finalDatetime = (new Date(bot.SESSION.parameters.timeRange.config.finalDatetime)).valueOf()
|
||||
bot.AI_SESSION.parameters.timeRange.config.finalDatetime = (new Date(bot.AI_SESSION.parameters.timeRange.config.finalDatetime)).valueOf()
|
||||
}
|
||||
}
|
||||
|
||||
/* Time Frame */
|
||||
if (bot.SESSION.parameters.timeFrame === undefined) {
|
||||
if (bot.AI_SESSION.parameters.timeFrame === undefined) {
|
||||
let errorMessage = "Session Parameters Node with no Time Frame."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION.parameters, errorMessage)
|
||||
bot.sessionError(bot.AI_SESSION.parameters, errorMessage)
|
||||
return false
|
||||
}
|
||||
if (bot.SESSION.parameters.timeFrame.config.label === undefined) {
|
||||
if (bot.AI_SESSION.parameters.timeFrame.config.label === undefined) {
|
||||
let errorMessage = "Session Parameters Node with no Time Frame Label configuration."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION.parameters.timeFrame, errorMessage)
|
||||
bot.sessionError(bot.AI_SESSION.parameters.timeFrame, errorMessage)
|
||||
return false
|
||||
}
|
||||
bot.SESSION.parameters.timeFrame.config.value = getTimeFrameFromLabel(bot.SESSION.parameters.timeFrame.config.label)
|
||||
if (bot.SESSION.parameters.timeFrame.config.value === undefined) {
|
||||
bot.AI_SESSION.parameters.timeFrame.config.value = getTimeFrameFromLabel(bot.AI_SESSION.parameters.timeFrame.config.label)
|
||||
if (bot.AI_SESSION.parameters.timeFrame.config.value === undefined) {
|
||||
let errorMessage = "Config error: label value not recognized. Try 01-min or 01-hs for example."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION.parameters.timeFrame, errorMessage)
|
||||
bot.sessionError(bot.AI_SESSION.parameters.timeFrame, errorMessage)
|
||||
return false
|
||||
}
|
||||
|
||||
/* Session Base Asset */
|
||||
if (bot.SESSION.parameters.sessionBaseAsset === undefined) {
|
||||
if (bot.AI_SESSION.parameters.sessionBaseAsset === undefined) {
|
||||
let errorMessage = "Session Parameters Node with no Session Base Asset."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION.parameters, errorMessage)
|
||||
bot.sessionError(bot.AI_SESSION.parameters, errorMessage)
|
||||
return false
|
||||
}
|
||||
if (bot.SESSION.parameters.sessionBaseAsset.config.initialBalance === undefined) {
|
||||
if (bot.AI_SESSION.parameters.sessionBaseAsset.config.initialBalance === undefined) {
|
||||
let errorMessage = "Session Parameters Session Base Asset with no initialBalance configuration."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION.parameters.sessionBaseAsset, errorMessage)
|
||||
bot.sessionError(bot.AI_SESSION.parameters.sessionBaseAsset, errorMessage)
|
||||
return false
|
||||
}
|
||||
|
||||
/* Session Quoted Asset */
|
||||
if (bot.SESSION.parameters.sessionQuotedAsset === undefined) {
|
||||
if (bot.AI_SESSION.parameters.sessionQuotedAsset === undefined) {
|
||||
let errorMessage = "Session Parameters Node with no Session Quoted Asset."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION.parameters, errorMessage)
|
||||
bot.sessionError(bot.AI_SESSION.parameters, errorMessage)
|
||||
return false
|
||||
}
|
||||
if (bot.SESSION.parameters.sessionQuotedAsset.config.initialBalance === undefined) {
|
||||
if (bot.AI_SESSION.parameters.sessionQuotedAsset.config.initialBalance === undefined) {
|
||||
let errorMessage = "Session Parameters Session Quoted Asset with no initialBalance configuration."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION.parameters.sessionQuotedAsset, errorMessage)
|
||||
bot.sessionError(bot.AI_SESSION.parameters.sessionQuotedAsset, errorMessage)
|
||||
return false
|
||||
}
|
||||
|
||||
/* Slippage */
|
||||
if (bot.SESSION.parameters.slippage === undefined) { // if the Slippage is missing we create a default one.
|
||||
bot.SESSION.parameters.slippage = {
|
||||
if (bot.AI_SESSION.parameters.slippage === undefined) { // if the Slippage is missing we create a default one.
|
||||
bot.AI_SESSION.parameters.slippage = {
|
||||
name: 'Missing Slippage',
|
||||
type: 'Slippage',
|
||||
config: {
|
||||
@@ -332,19 +332,19 @@ exports.newTrainingSession = function newTrainingSession(bot, parentLogger) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bot.SESSION.parameters.slippage.config.marketOrderRate === undefined) { // if the marketOrderRate is missing we create a default one.
|
||||
bot.SESSION.parameters.slippage.config.marketOrderRate = 0
|
||||
if (bot.AI_SESSION.parameters.slippage.config.marketOrderRate === undefined) { // if the marketOrderRate is missing we create a default one.
|
||||
bot.AI_SESSION.parameters.slippage.config.marketOrderRate = 0
|
||||
}
|
||||
if (bot.SESSION.parameters.slippage.config.stopLoss === undefined) { // if the stopLoss is missing we create a default one.
|
||||
bot.SESSION.parameters.slippage.config.stopLoss = 0
|
||||
if (bot.AI_SESSION.parameters.slippage.config.stopLoss === undefined) { // if the stopLoss is missing we create a default one.
|
||||
bot.AI_SESSION.parameters.slippage.config.stopLoss = 0
|
||||
}
|
||||
if (bot.SESSION.parameters.slippage.config.takeProfit === undefined) { // if the takeProfit is missing we create a default one.
|
||||
bot.SESSION.parameters.slippage.config.takeProfit = 0
|
||||
if (bot.AI_SESSION.parameters.slippage.config.takeProfit === undefined) { // if the takeProfit is missing we create a default one.
|
||||
bot.AI_SESSION.parameters.slippage.config.takeProfit = 0
|
||||
}
|
||||
|
||||
/* Fee Structure */
|
||||
if (bot.SESSION.parameters.feeStructure === undefined) { // if the Fee Structure is missing we create a default one.
|
||||
bot.SESSION.parameters.feeStructure = {
|
||||
if (bot.AI_SESSION.parameters.feeStructure === undefined) { // if the Fee Structure is missing we create a default one.
|
||||
bot.AI_SESSION.parameters.feeStructure = {
|
||||
name: 'Missing Fee Structure',
|
||||
type: 'Fee Structure',
|
||||
config: {
|
||||
@@ -353,11 +353,11 @@ exports.newTrainingSession = function newTrainingSession(bot, parentLogger) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bot.SESSION.parameters.feeStructure.config.maker === undefined) { // if the maker is missing we create a default one.
|
||||
bot.SESSION.parameters.feeStructure.config.maker = 0
|
||||
if (bot.AI_SESSION.parameters.feeStructure.config.maker === undefined) { // if the maker is missing we create a default one.
|
||||
bot.AI_SESSION.parameters.feeStructure.config.maker = 0
|
||||
}
|
||||
if (bot.SESSION.parameters.feeStructure.config.taker === undefined) { // if the taker is missing we create a default one.
|
||||
bot.SESSION.parameters.feeStructure.config.taker = 0
|
||||
if (bot.AI_SESSION.parameters.feeStructure.config.taker === undefined) { // if the taker is missing we create a default one.
|
||||
bot.AI_SESSION.parameters.feeStructure.config.taker = 0
|
||||
}
|
||||
|
||||
return true
|
||||
@@ -371,7 +371,7 @@ exports.newTrainingSession = function newTrainingSession(bot, parentLogger) {
|
||||
if (bot.KEY === undefined || bot.SECRET === undefined) {
|
||||
let errorMessage = "Key 'codeName' or 'secret' not provided. Plese check that and try again."
|
||||
if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, "[ERROR] initialize -> startLiveTrading -> " + errorMessage); }
|
||||
bot.sessionError(bot.SESSION, errorMessage)
|
||||
bot.sessionError(bot.AI_SESSION, errorMessage)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -387,20 +387,20 @@ exports.newTrainingSession = function newTrainingSession(bot, parentLogger) {
|
||||
/* Reduce the balance */
|
||||
let balancePercentage = 1 // This is the default value
|
||||
|
||||
if (bot.SESSION.config.balancePercentage !== undefined) {
|
||||
balancePercentage = bot.SESSION.config.balancePercentage
|
||||
if (bot.AI_SESSION.config.balancePercentage !== undefined) {
|
||||
balancePercentage = bot.AI_SESSION.config.balancePercentage
|
||||
}
|
||||
|
||||
bot.SESSION.parameters.sessionBaseAsset.config.initialBalance = bot.SESSION.parameters.sessionBaseAsset.config.initialBalance * balancePercentage / 100
|
||||
bot.SESSION.parameters.sessionQuotedAsset.config.initialBalance = bot.SESSION.parameters.sessionQuotedAsset.config.initialBalance * balancePercentage / 100
|
||||
bot.AI_SESSION.parameters.sessionBaseAsset.config.initialBalance = bot.AI_SESSION.parameters.sessionBaseAsset.config.initialBalance * balancePercentage / 100
|
||||
bot.AI_SESSION.parameters.sessionQuotedAsset.config.initialBalance = bot.AI_SESSION.parameters.sessionQuotedAsset.config.initialBalance * balancePercentage / 100
|
||||
|
||||
bot.SESSION.parameters.sessionBaseAsset.config.minimumBalance = bot.SESSION.parameters.sessionBaseAsset.config.minimumBalance * balancePercentage / 100
|
||||
bot.SESSION.parameters.sessionQuotedAsset.config.minimumBalance = bot.SESSION.parameters.sessionQuotedAsset.config.minimumBalance * balancePercentage / 100
|
||||
bot.AI_SESSION.parameters.sessionBaseAsset.config.minimumBalance = bot.AI_SESSION.parameters.sessionBaseAsset.config.minimumBalance * balancePercentage / 100
|
||||
bot.AI_SESSION.parameters.sessionQuotedAsset.config.minimumBalance = bot.AI_SESSION.parameters.sessionQuotedAsset.config.minimumBalance * balancePercentage / 100
|
||||
|
||||
bot.SESSION.parameters.sessionBaseAsset.config.maximumBalance = bot.SESSION.parameters.sessionBaseAsset.config.maximumBalance * balancePercentage / 100
|
||||
bot.SESSION.parameters.sessionQuotedAsset.config.maximumBalance = bot.SESSION.parameters.sessionQuotedAsset.config.maximumBalance * balancePercentage / 100
|
||||
bot.AI_SESSION.parameters.sessionBaseAsset.config.maximumBalance = bot.AI_SESSION.parameters.sessionBaseAsset.config.maximumBalance * balancePercentage / 100
|
||||
bot.AI_SESSION.parameters.sessionQuotedAsset.config.maximumBalance = bot.AI_SESSION.parameters.sessionQuotedAsset.config.maximumBalance * balancePercentage / 100
|
||||
|
||||
pProcessConfig.normalWaitTime = bot.SESSION.parameters.timeFrame.config.value
|
||||
pProcessConfig.normalWaitTime = bot.AI_SESSION.parameters.timeFrame.config.value
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ global.ROOT_DIR = './';
|
||||
global.ONE_YEAR_IN_MILISECONDS = 365 * 24 * 60 * 60 * 1000
|
||||
global.ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000
|
||||
global.ONE_MIN_IN_MILISECONDS = 60 * 1000
|
||||
global.LOGGER_MAP = new Map()
|
||||
global.SESSION_MAP = new Map()
|
||||
global.LOGGER_MAP = new Map() // We will put all the loggers in a map, so that we can eventually finalize them.
|
||||
global.SESSION_MAP = new Map() // We will put all the sessions in a map, so that we can eventually finalize them.
|
||||
|
||||
global.UNIQUE_ID = function () {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
||||
|
||||
Reference in new issue
Block a user