Compare commits

..
14 changed files with 366 additions and 114 deletions

No files matched your search

+5
View File
@@ -2881,6 +2881,11 @@
"actionFunction": "payload.onMenuItemClick"
}
],
"isTitleAllwaysVisible": true,
"title": [
"Use Reference Parent Parent Parent",
"Use Reference Parent Parent"
],
"addLeftIcons": true,
"level": 3,
"referenceAttachesTo": {
+9 -5
View File
@@ -183,16 +183,20 @@
function listenToEvent(eventHandlerName, eventType, callerId, handler, extraData) {
let eventSubscriptionId = Math.trunc(Math.random() * 1000000)
let found = false
/*
We can not allow to have the exact same listener more than once. In case that we find a listener trying to listen again, the first record will
be deleted and we are just going to consider the last one comming in.
*/
for (let i = 0; i < thisObject.listeners.length; i++) {
if (eventHandlerName === thisObject.listeners[i][0] && eventType === thisObject.listeners[i][1] && callerId === thisObject.listeners[i][2]) {
found = true
thisObject.listeners.splice(i, 1)
break
}
}
if (found === false) {
thisObject.listeners.push([eventHandlerName, eventType, callerId, handler, extraData, eventSubscriptionId])
}
thisObject.listeners.push([eventHandlerName, eventType, callerId, handler, extraData, eventSubscriptionId])
return eventSubscriptionId
}
+2 -1
View File
@@ -66,7 +66,8 @@
}
if (tasks.get(message.event.taskId) !== undefined) {
//console.log('[WARN] BackendServers -> Task Manager Server -> runTask -> Task Already Running -> taskId = ' + message.event.taskId)
let key = message.event.taskName + '-' + 'Task' + '-' + message.event.taskId
eventsServerClient.raiseEvent(key, 'Running') // Meaning Task Running
return
}
//console.log('[INFO] BackendServers -> Task Manager Server -> runTask -> Task Name = ' + message.event.taskName)
@@ -19,8 +19,14 @@ function newReferenceAttachDetach () {
}
function completeDetachment (node) {
if (node.payload.referenceParent.payload !== undefined && node.payload.referenceParent.payload.uiObject !== undefined) {
node.payload.referenceParent.payload.uiObject.isShowing = false
if (node.payload !== undefined !== undefined) {
if (node.payload.referenceParent !== undefined) {
if (node.payload.referenceParent.payload !== undefined) {
if (node.payload.referenceParent.payload.uiObject !== undefined) {
node.payload.referenceParent.payload.uiObject.isShowing = false
}
}
}
}
node.payload.referenceParent = undefined
@@ -21,7 +21,7 @@ function newSessionFunctions () {
}
if (node.payload.referenceParent === undefined) {
node.payload.uiObject.setErrorMessage('Parent Process Instance need to reference a Process Definition.')
node.payload.uiObject.setErrorMessage('Session needs to reference a Trading System.')
callBackFunction(GLOBAL.DEFAULT_FAIL_RESPONSE)
return
}
+4
View File
@@ -202,6 +202,8 @@ function newPlotter () {
if (newMarketFile !== undefined) {
marketFile = newMarketFile
recalculate()
} else {
logger.write('[WARN] setTimeFrame -> Could not change to market file for timeFrame = ' + pTimeFrame)
}
} else {
let newFileCursor = dailyFiles.getFileCursor(pTimeFrame)
@@ -209,6 +211,8 @@ function newPlotter () {
if (newFileCursor !== undefined) {
fileCursor = newFileCursor
recalculate()
} else {
logger.write('[WARN] setTimeFrame -> Could not change to market file for timeFrame = ' + pTimeFrame)
}
}
}
+16 -3
View File
@@ -73,9 +73,22 @@ function newDashboard () {
}
function setBrowserEvents () {
window.onbeforeunload = onBrowserClosed
function onBrowserClosed () {
// canvas.designSpace.workspace.stopAllRunningTasks()
window.onbeforeunload = saveWorkspace
/* handles backspace and refresh(F5) from keyboard */
window.manageBackRefresh = function (event) {
var tag = event.target.tagName.toLowerCase()
if (event.keyCode == 8 && tag != 'input' && tag != 'textarea') { // Backbutton pressed
saveWorkspace()
} else if (event.keyCode == 116) { // F5 pressed
saveWorkspace()
}
}
window.addEventListener('keydown', window.manageBackRefresh)
function saveWorkspace () {
canvas.designSpace.workspace.save()
}
}
}
@@ -354,6 +354,11 @@ exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, FILE_S
return
}
if (err.stack.toString().indexOf('ExchangeNotAvailable') >= 0) {
logger.write(MODULE_NAME, "[ERROR] start -> getOHLCVs -> Retrying Later -> The Exchange " + bot.exchange + " is not responding at the moment. I will save the data already fetched and try to reconnect later to fetch the rest of the missing data.");
return
}
logger.write(MODULE_NAME, "[ERROR] start -> getOHLCVs -> Retrying Later -> err = " + err.stack);
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
abort = true
+29
View File
@@ -289,6 +289,35 @@
let variable = {} // This is the structure where the user will define its own variables that will be shared across different code blocks and formulas.
let results = []
/*
We are going to build a map structure so that users can easily get the current object of
each data dependency based on the current element of the main data dependency.
We will use as key for these maps the begin and end property, meaning only elements with exactly
the same begin and end property will be matched.
*/
const PROPERTIES_COUNT = Object.keys(products).length
let dataDependencies = {}
if (PROPERTIES_COUNT > 1) { // only if we have secondary data dependencies.
for (let i = 1; i < PROPERTIES_COUNT; i++) {
let dataDependecyArray = Object.values(products)[i]
let dataDependencyName = Object.keys(products)[i]
let dataDependencyMap = new Map()
for (let j = 0; j < dataDependecyArray.length; j++) {
let record = dataDependecyArray[j]
let key = record.begin.toString() + '-' + record.end.toString()
dataDependencyMap.set(key, record)
}
dataDependencies[dataDependencyName] = dataDependencyMap
}
}
function getElement(dependencyName, currentRecordPrimaryDataDependency) {
let key = currentRecordPrimaryDataDependency.begin.toString() + '-' + currentRecordPrimaryDataDependency.end.toString()
return dataDependencies[dependencyName].get(key)
}
/* This is Initialization Code */
if (dataBuildingProcedure.initialization !== undefined) {
if (dataBuildingProcedure.initialization.javascriptCode !== undefined) {
+4 -2
View File
@@ -61,7 +61,7 @@ exports.newDebugLog = function newDebugLog() {
function persist() {
/* Here we actually write the content of the in-memory log to a blob */
/* Here we actually write the content of the in-memory log to a file */
try {
@@ -96,7 +96,9 @@ exports.newDebugLog = function newDebugLog() {
writeLog();
/* This is the implementation of the mechanism to auto-mantain logs. */
thisObject.bot.LOGS_TO_DELETE_QUEUE.push(filePath + '/' + fileName)
if (contentToPersist.indexOf('[ERROR]') < 0) {
thisObject.bot.LOGS_TO_DELETE_QUEUE.push(filePath + '/' + fileName)
}
if (thisObject.bot.LOGS_TO_DELETE_QUEUE.length > thisObject.bot.DELETE_QUEUE_SIZE) {
let fileToDelete = thisObject.bot.LOGS_TO_DELETE_QUEUE[0]
thisObject.bot.LOGS_TO_DELETE_QUEUE.splice(0, 1)
+138 -34
View File
@@ -24,13 +24,13 @@ exports.newFileStorage = function newFileStorage(logger) {
return thisObject
function getTextFile(filePath, callBackFunction, noRetry) {
function getTextFile(filePath, callBackFunction, noRetry, canUsePrevious) {
let currentRetryGetTextFile = 0
recursiveGetTextFile(filePath, callBackFunction, noRetry)
recursiveGetTextFile(filePath, callBackFunction, noRetry, canUsePrevious)
function recursiveGetTextFile(filePath, callBackFunction, noRetry) {
function recursiveGetTextFile(filePath, callBackFunction, noRetry, canUsePrevious) {
logger.write(MODULE_NAME, '[INFO] FileStorage -> getTextFile -> Entering Function.')
@@ -38,10 +38,13 @@ exports.newFileStorage = function newFileStorage(logger) {
/* Choose path for either bots or data */
let fileLocation
let mustBeJason
if (filePath.indexOf("/bots/") > 0) {
fileLocation = process.env.BOTS_PATH + '/' + filePath
mustBeJason = false
} else {
fileLocation = process.env.STORAGE_PATH + '/' + filePath
mustBeJason = true
}
try {
@@ -68,12 +71,12 @@ exports.newFileStorage = function newFileStorage(logger) {
}
callBackFunction(customResponse)
return
} else {
fileDoesNotExist = true
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> File does not exist. Retrying. ')
setTimeout(retry, retryTimeToUse)
return
}
}
fileDoesNotExist = true
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> File does not exist. Retrying. ')
setTimeout(retry, retryTimeToUse)
return
}
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Error reading file -> err = ' + err.stack)
@@ -83,13 +86,60 @@ exports.newFileStorage = function newFileStorage(logger) {
return
}
if (text.toString() === "") {
/*
It might happen that we try to read a file just at the moment it is being written by another process. It that case we might get
an empty file. If we are not allowed to use the Previous version of the file in this case, then we will retry to read it again
a little bit later.
*/
if (text.toString() === "" && canUsePrevious !== true) {
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Read and Empty File -> filePath = ' + filePath)
setTimeout(retry, retryTimeToUse)
return
}
callBackFunction(global.DEFAULT_OK_RESPONSE, text.toString())
if (mustBeJason === false) {
/* In this case there is nothing else to check. */
callBackFunction(global.DEFAULT_OK_RESPONSE, text.toString())
return
}
/*
We are going to check if the file is a valir JSON object
*/
try {
let jsonCheck = JSON.parse(text.toString())
/* The file was correctly read and could be parsed. */
callBackFunction(global.DEFAULT_OK_RESPONSE, text.toString())
return
} catch (err) {
if (canUsePrevious === true) {
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Could read the file, but could not parse it as it is not a valid JSON. Will try to read the PREVIOUS version instead. -> file = ' + fileLocation)
fs.readFile(fileLocation + '.Previous.json', onPreviousFileRead)
function onPreviousFileRead(err, text) {
if (err) {
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> canUsePrevious -> Could not read the Previous file either. Giving up.')
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> canUsePrevious -> err = ' + err.stack)
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
return
}
/* Returning the previous file */
callBackFunction(global.DEFAULT_OK_RESPONSE, text.toString())
return
}
} else {
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Could read the file, but could not parse it as it is not a valid JSON.')
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> err = ' + err.stack)
setTimeout(retry, retryTimeToUse)
return
}
}
}
} catch (err) {
@@ -103,7 +153,7 @@ exports.newFileStorage = function newFileStorage(logger) {
if (currentRetryGetTextFile < MAX_RETRY) {
currentRetryGetTextFile++
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> retry -> Will try to read the file again -> Retry #: ' + currentRetryGetTextFile)
recursiveGetTextFile(filePath, callBackFunction)
recursiveGetTextFile(filePath, callBackFunction, noRetry, canUsePrevious)
} else {
currentRetryGetTextFile = 0
@@ -116,6 +166,7 @@ exports.newFileStorage = function newFileStorage(logger) {
callBackFunction(customResponse)
return
} else {
logger.write(MODULE_NAME, '[ERROR] FileStorage -> getTextFile -> retry -> Max retries reached reading a file. Giving up.')
logger.write(MODULE_NAME, '[ERROR] FileStorage -> getTextFile -> retry -> file = ' + fileLocation)
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
@@ -126,13 +177,13 @@ exports.newFileStorage = function newFileStorage(logger) {
}
}
function createTextFile(filePath, fileContent, callBackFunction) {
function createTextFile(filePath, fileContent, callBackFunction, keepPrevious) {
let currentRetryWriteTextFile = 0
recursiveCreateTextFile(filePath, fileContent, callBackFunction)
recursiveCreateTextFile(filePath, fileContent, callBackFunction, keepPrevious)
function recursiveCreateTextFile(filePath, fileContent, callBackFunction) {
function recursiveCreateTextFile(filePath, fileContent, callBackFunction, keepPrevious) {
logger.write(MODULE_NAME, '[INFO] FileStorage -> createTextFile -> Entering Function.')
@@ -165,32 +216,85 @@ exports.newFileStorage = function newFileStorage(logger) {
retryTimeToUse = SLOW_RETRY_TIME_IN_MILISECONDS
}
if (err) {
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> Error writing file -> file = ' + fileLocation)
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> Error writing file -> file = ' + fileLocation + '.tmp')
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> Error writing file -> err = ' + err.stack)
setTimeout(retry, retryTimeToUse)
} else {
const fs = require('fs')
fs.unlink(fileLocation, onUnlinked)
if (keepPrevious === true) {
/*
In some cases, we are going to keep a copy of the previous version of the file being written. This will be usefull to recover from crashes
when the file written gets corrupted for any reason.
*/
fs.unlink(fileLocation + '.Previous.json', onUnlinked)
function onUnlinked(err) {
let code = ''
if (err) {
code = err.code
}
if (code !== '' && code !== 'ENOENT') {
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error renaming file -> file = ' + fileLocation)
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error renaming file -> err = ' + err.stack)
setTimeout(retry, retryTimeToUse)
} else {
function onUnlinked(err) {
let code = ''
if (err) {
code = err.code
}
if (code !== '' && code !== 'ENOENT') {
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error deleting file -> file = ' + fileLocation + '.Previous.json')
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error deleting file -> err = ' + err.stack)
setTimeout(retry, retryTimeToUse)
return
}
const fs = require('fs')
fs.rename(fileLocation + '.tmp', fileLocation, onRenamed)
/* Rename de Original into Previous */
fs.rename(fileLocation, fileLocation + '.Previous.json', onOriginalRenamed)
function onRenamed(err) {
function onOriginalRenamed(err) {
let code = ''
if (err) {
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> onRenamed -> Error renaming file -> file = ' + fileLocation + '.tmp')
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> onRenamed -> Error renaming file -> err = ' + err.stack)
code = err.code
}
if (code !== '' && code !== 'ENOENT') { // Unless the file does not exists we do this...
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> onOriginalRenamed -> Error renaming original file -> file = ' + fileLocation)
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> onOriginalRenamed -> Error renaming original file -> err = ' + err.stack)
setTimeout(retry, retryTimeToUse)
return
}
/* Rename de Temp into Original */
fs.rename(fileLocation + '.tmp', fileLocation, onTempRenamed)
function onTempRenamed(err) {
if (err) {
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> onOriginalRenamed -> onTempRenamed -> Error renaming temp file -> file = ' + fileLocation + '.tmp')
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> onOriginalRenamed -> onTempRenamed -> Error renaming temp file -> err = ' + err.stack)
setTimeout(retry, retryTimeToUse)
} else {
callBackFunction(global.DEFAULT_OK_RESPONSE)
}
}
}
}
} else {
/* In this case, there is no need to keep a copy of the file being replaced, so we just delete and that's it. */
fs.unlink(fileLocation , onUnlinked)
function onUnlinked(err) {
let code = ''
if (err) {
code = err.code
}
if (code !== '' && code !== 'ENOENT') {
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error deleting file -> file = ' + fileLocation )
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> Error deleting file -> err = ' + err.stack)
setTimeout(retry, retryTimeToUse)
return
}
/* Rename de Temp into Original */
fs.rename(fileLocation + '.tmp', fileLocation, onTempRenamed)
function onTempRenamed(err) {
if (err) {
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> onOriginalRenamed -> onTempRenamed -> Error renaming temp file -> file = ' + fileLocation + '.tmp')
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> onFileWriten -> onUnlinked -> onOriginalRenamed -> onTempRenamed -> Error renaming temp file -> err = ' + err.stack)
setTimeout(retry, retryTimeToUse)
} else {
@@ -213,7 +317,7 @@ exports.newFileStorage = function newFileStorage(logger) {
if (currentRetryWriteTextFile < MAX_RETRY) {
currentRetryWriteTextFile++
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> retry -> Will try to write the file again -> Retry #: ' + currentRetryWriteTextFile)
recursiveCreateTextFile(filePath, fileContent, callBackFunction)
recursiveCreateTextFile(filePath, fileContent, callBackFunction, keepPrevious)
} else {
currentRetryWriteTextFile = 0
logger.write(MODULE_NAME, '[ERROR] FileStorage -> createTextFile -> retry -> Max retries reached writting a file. Giving up.')
+120 -61
View File
@@ -10,10 +10,12 @@
return thisObject;
function initialize(callBackFunction) {
function initialize(pProcessConfig, callBackFunction) {
try {
if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); }
let telegramAPI
/* Initialize this info so that everything is logged propeerly */
bot.SESSION = {
@@ -45,66 +47,79 @@
return
function runSession(message) {
if (bot.SESSION_STATUS === 'Idle' || bot.SESSION_STATUS === 'Running') { return } // This happens when the UI is reloaded, the session was running and tries to run it again.
/* We are going to run the Definition comming at the event. */
bot.TRADING_SYSTEM = JSON.parse(message.event.tradingSystem)
bot.SESSION = JSON.parse(message.event.session)
/* Set the folderName for logging, reports, context and data output */
let code
if (bot.SESSION.code !== undefined) {
code = bot.SESSION.code
if (code.folderName === undefined) {
bot.SESSION.folderName = bot.SESSION.id
try {
if (bot.SESSION_STATUS === 'Idle' || bot.SESSION_STATUS === 'Running') { return } // This happens when the UI is reloaded, the session was running and tries to run it again.
/* We are going to run the Definition comming at the event. */
bot.TRADING_SYSTEM = JSON.parse(message.event.tradingSystem)
bot.SESSION = JSON.parse(message.event.session)
/* Set the folderName for logging, reports, context and data output */
let code
if (bot.SESSION.code !== undefined) {
code = bot.SESSION.code
if (code.folderName === undefined) {
bot.SESSION.folderName = bot.SESSION.id
} else {
bot.SESSION.folderName = code.folderName + "-" + bot.SESSION.id
}
}
/* Extract values from different sources and consolidate them under one structure that is going to be used later on. */
setValuesToUse(message)
/* Set up Social Bots */
initializeSocialBots()
let allGood
switch (bot.SESSION.type) {
case 'Backtesting Session': {
allGood = startBackTesting(message)
break
}
case 'Live Trading Session': {
allGood = startLiveTrading(message)
break
}
case 'Fordward Testing Session': {
allGood = startFordwardTesting(message)
break
}
case 'Paper Trading Session': {
allGood = startPaperTrading(message)
break
}
}
if (allGood === true) {
bot.SESSION_STATUS = 'Idle'
bot.STOP_SESSION = false
} else {
bot.SESSION.folderName = code.folderName + "-" + bot.SESSION.id
bot.STOP_SESSION = true
}
}
/* Set up Social Bots */
setUpSocialBots()
/* Extract values from different sources and consolidate them under one structure that is going to be used later on. */
setValuesToUse(message)
let allGood
switch (bot.SESSION.type) {
case 'Backtesting Session': {
allGood = startBackTesting(message)
break
}
case 'Live Trading Session': {
allGood = startLiveTrading(message)
break
}
case 'Fordward Testing Session': {
allGood = startFordwardTesting(message)
break
}
case 'Paper Trading Session': {
allGood = startPaperTrading(message)
break
}
}
if (allGood === true) {
bot.SESSION_STATUS = 'Idle'
bot.STOP_SESSION = false
} else {
bot.STOP_SESSION = true
} catch (err) {
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> runSession -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function stopSession(message) {
bot.STOP_SESSION = true
try {
bot.STOP_SESSION = true
finalizeSocialBots()
} catch (err) {
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> stopSession -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function checkDatetimes() {
if (bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf() < (new Date()).valueOf()) {
if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, "[WARN] initialize -> startLiveTrading -> Overriding initialDatetime with present datetime because " + bot.VALUES_TO_USE.timeRange.initialDatetime + " is in the past."); }
if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, "[WARN] initialize -> checkDatetimes -> Overriding initialDatetime with present datetime because " + bot.VALUES_TO_USE.timeRange.initialDatetime + " is in the past."); }
bot.VALUES_TO_USE.timeRange.initialDatetime = new Date()
}
if (bot.VALUES_TO_USE.timeRange.finalDatetime.valueOf() < (new Date()).valueOf()) {
if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, "[WARN] initialize -> startLiveTrading -> Overriding finalDatetime with present datetime plus one year because " + bot.VALUES_TO_USE.timeRange.finalDatetime + " is in the past."); }
if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, "[WARN] initialize -> checkDatetimes -> Overriding finalDatetime with present datetime plus one year because " + bot.VALUES_TO_USE.timeRange.finalDatetime + " is in the past."); }
bot.VALUES_TO_USE.timeRange.finalDatetime = new Date() + ONE_YEAR_IN_MILISECONDS
}
}
@@ -133,13 +148,14 @@
bot.resumeExecution = false;
bot.multiPeriodProcessDatetime = new Date(bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf())
bot.hasTheBotJustStarted = true
pProcessConfig.liveWaitTime = getTimeFrameFromLabel(bot.VALUES_TO_USE.timeFrame)
return true
}
function startFordwardTesting(message) {
if (process.env.KEY === undefined || process.env.SECRET === undefined) {
if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, "[WARN] initialize -> startLiveTrading -> Key name or Secret not provided, not possible to run the process in Forward Testing mode."); }
if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, "[WARN] initialize -> startFordwardTesting -> Key name or Secret not provided, not possible to run the process in Forward Testing mode."); }
console.log("Key 'codeName' or 'secret' not provided. Plese check that and try again.")
return
}
@@ -166,6 +182,9 @@
bot.VALUES_TO_USE.maximumBalanceA = bot.VALUES_TO_USE.maximumBalanceA * balancePercentage / 100
bot.VALUES_TO_USE.maximumBalanceB = bot.VALUES_TO_USE.maximumBalanceB * balancePercentage / 100
pProcessConfig.normalWaitTime = getTimeFrameFromLabel(bot.VALUES_TO_USE.timeFrame)
return true
}
@@ -176,9 +195,31 @@
bot.resumeExecution = false;
bot.hasTheBotJustStarted = true
bot.multiPeriodProcessDatetime = new Date(bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf())
pProcessConfig.normalWaitTime = getTimeFrameFromLabel(bot.VALUES_TO_USE.timeFrame)
return true
}
function getTimeFrameFromLabel(timeFrameLabel) {
for (let i = 0; i < global.marketFilesPeriods.length; i++) {
let value = global.marketFilesPeriods[i][0]
let label = global.marketFilesPeriods[i][1]
if (timeFrameLabel === label) {
return value
}
}
for (let i = 0; i < global.dailyFilePeriods.length; i++) {
let value = global.dailyFilePeriods[i][0]
let label = global.dailyFilePeriods[i][1]
if (timeFrameLabel === label) {
return value
}
}
}
function setValuesToUse(message) {
/*
Base on the information received we will determined which values ultimatelly are going to be used,
@@ -378,7 +419,7 @@
}
}
function setUpSocialBots() {
function initializeSocialBots() {
if (bot.SESSION.socialBots !== undefined) {
if (bot.SESSION.socialBots.bots !== undefined) {
@@ -386,7 +427,7 @@
let socialBot = bot.SESSION.socialBots.bots[i]
if (socialBot.type === "Telegram Bot") {
let code = socialBot.code
socialBot.botInstance = setUpTelegramBot(code.botToken, code.chatId)
socialBot.botInstance = initializeTelegramBot(code.botToken, code.chatId)
}
}
}
@@ -400,14 +441,14 @@
if (socialBot.type === "Telegram Bot") {
if (announcement.formulaValue !== undefined) {
socialBot.botInstance.telegramAPI.sendMessage(socialBot.botInstance.chatId, announcement.formulaValue).catch(err => parentLogger.write(MODULE_NAME, "[WARN] initialize -> setUpSocialBots -> announce -> Telegram API error -> err = " + err))
socialBot.botInstance.telegramAPI.sendMessage(socialBot.botInstance.chatId, announcement.formulaValue).catch(err => parentLogger.write(MODULE_NAME, "[WARN] initialize -> initializeSocialBots -> announce -> Telegram API error -> err = " + err))
} else {
socialBot.botInstance.telegramAPI.sendMessage(socialBot.botInstance.chatId, code.text).catch(err => parentLogger.write(MODULE_NAME, "[WARN] initialize -> setUpSocialBots -> announce -> Telegram API error -> err = " + err))
socialBot.botInstance.telegramAPI.sendMessage(socialBot.botInstance.chatId, code.text).catch(err => parentLogger.write(MODULE_NAME, "[WARN] initialize -> initializeSocialBots -> announce -> Telegram API error -> err = " + err))
}
}
} catch (err) {
parentLogger.write(MODULE_NAME, "[WARN] initialize -> setUpSocialBots -> announce -> err = " + err.stack);
parentLogger.write(MODULE_NAME, "[WARN] initialize -> initializeSocialBots -> announce -> err = " + err.stack);
}
}
}
@@ -417,22 +458,35 @@
}
}
function setUpTelegramBot(botToken, chatId) {
function finalizeSocialBots() {
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 (socialBot.type === "Telegram Bot") {
let code = socialBot.code
socialBot.botInstance = finalizeTelegramBot(code.chatId)
}
}
}
}
function initializeTelegramBot(botToken, chatId) {
/* Telegram Bot Initialization */
try {
const Telegraf = require('telegraf')
let telegramBot
telegramBot = new Telegraf(botToken)
telegramBot.start((ctx) => ctx.reply('Hi! I am a Telegram Bot powered by Superalgos'))
telegramBot.help((ctx) => ctx.reply('Send me a sticker'))
telegramBot.on('sticker', (ctx) => ctx.reply('??'))
telegramBot.hears('hi', (ctx) => ctx.reply('Hey there'))
telegramBot.start((ctx) => ctx.reply('Hi! I am the Telegram Bot that will tell you what happens with your trading session.'))
telegramBot.help((ctx) => ctx.reply('I can stop the session if you say STOP.'))
telegramBot.hears('STOP', (ctx) => stopSession())
telegramBot.launch()
const Telegram = require('telegraf/telegram')
let telegramAPI
telegramAPI = new Telegram(botToken)
telegramAPI.sendMessage(chatId, bot.SESSION.type + " '" + bot.SESSION.name + "' was Started.").catch(err => parentLogger.write(MODULE_NAME, "[WARN] initialize -> setUpTelegramBot -> Telegram API error -> err = " + err))
const messge = bot.SESSION.type + " '" + bot.SESSION.name + "' was started with an initial balance of " + " " + bot.VALUES_TO_USE.initialBalanceA + " " + bot.VALUES_TO_USE.baseAsset + "."
telegramAPI.sendMessage(chatId, messge ).catch(err => parentLogger.write(MODULE_NAME, "[WARN] initialize -> initializeTelegramBot -> Telegram API error -> err = " + err))
let botInstance = {
telegramBot: telegramBot,
@@ -441,10 +495,15 @@
}
return botInstance
} catch (err) {
parentLogger.write(MODULE_NAME, "[WARN] initialize -> setUpTelegramBot -> err = " + err.stack);
parentLogger.write(MODULE_NAME, "[WARN] initialize -> initializeTelegramBot -> err = " + err.stack);
}
}
function finalizeTelegramBot(chatId) {
const messge = bot.SESSION.type + " '" + bot.SESSION.name + "' was stopped."
telegramAPI.sendMessage(chatId, messge).catch(err => parentLogger.write(MODULE_NAME, "[WARN] initialize -> initializeTelegramBot -> Telegram API error -> err = " + err))
}
} catch (err) {
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack);
+16 -2
View File
@@ -153,7 +153,21 @@
filePath += '/' + fileName
fileStorage.getTextFile(filePath, onFileReceived);
let canUserPrevious
/*
If we are funning Trading Engines, we can not allow ourselves to use a Status Report that is not the latest one, because it might contain
transactioinal information related to the context of the operations the trading engine is doing.
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) {
canUserPrevious = false
} else {
canUserPrevious = true
}
fileStorage.getTextFile(filePath, onFileReceived, undefined, canUserPrevious);
function onFileReceived(err, text) {
@@ -241,7 +255,7 @@
filePath += '/' + fileName
let fileContent = JSON.stringify(thisObject.file);
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated);
fileStorage.createTextFile(filePath, fileContent + '\n', onFileCreated, true);
function onFileCreated(err) {
+9 -3
View File
@@ -43,7 +43,7 @@
if (bot.definedByUI === true) {
/* The code of the bot is defined at the UI. No need to load a file with the code. */
session.initialize(onSessionInitialized)
session.initialize(processConfig, onSessionInitialized)
function onSessionInitialized(err) {
callBackFunction(err);
@@ -902,12 +902,18 @@
waitTime = processConfig.normalWaitTime
}
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (waitTime / 1000) + " seconds."); }
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (waitTime / 1000 / 60) + " minute/s."); }
if (processConfig.deadWaitTime > 0) {
checkLoopHealthHandle = setTimeout(checkLoopHealth, processConfig.deadWaitTime, bot.loopCounter);
}
nextLoopTimeoutHandle = setTimeout(loop, waitTime);
processHeartBeat(undefined, undefined, "Waiting " + waitTime / 1000 + " seconds for next execution.")
let waitingTime = waitTime / 1000 / 60
let label = 'minute/s'
if (waitingTime < 1) {
waitingTime = waitTime / 1000
label = 'seconds'
}
processHeartBeat(undefined, undefined, "Waiting " + waitingTime + " " + label + " for next execution.")
if (global.WRITE_LOGS_TO_FILES === 'true') {
logger.persist();
}