5 files changed
+427
-476
No files matched your search
+203
-182
@@ -6,10 +6,7 @@ exports.newFileStorage = function newFileStorage(logger) {
|
||||
const MODULE_NAME = 'FileStorage'
|
||||
const MAX_RETRY = 30
|
||||
const FAST_RETRY_TIME_IN_MILISECONDS = 500
|
||||
const SLOW_RETRY_TIME_IN_MILISECONDS = 5000
|
||||
let currentRetryGetTextFile = 0
|
||||
let currentRetryWriteTextFile = 0
|
||||
let currentRetryDeleteTextFile = 0
|
||||
const SLOW_RETRY_TIME_IN_MILISECONDS = 2000
|
||||
|
||||
if (logger === undefined) { // Dummy logger
|
||||
logger = {}
|
||||
@@ -29,94 +26,101 @@ exports.newFileStorage = function newFileStorage(logger) {
|
||||
|
||||
function getTextFile(filePath, callBackFunction, noRetry) {
|
||||
|
||||
logger.write(MODULE_NAME, '[INFO] FileStorage -> getTextFile -> Entering Function.')
|
||||
let currentRetryGetTextFile = 0
|
||||
|
||||
let fileDoesNotExist = false
|
||||
recursiveGetTextFile(filePath, callBackFunction, noRetry)
|
||||
|
||||
/* Choose path for either bots or data */
|
||||
let fileLocation
|
||||
if (filePath.indexOf("/bots/") > 0) {
|
||||
fileLocation = process.env.BOTS_PATH + '/' + filePath
|
||||
} else {
|
||||
fileLocation = process.env.STORAGE_PATH + '/' + filePath
|
||||
}
|
||||
function recursiveGetTextFile(filePath, callBackFunction, noRetry) {
|
||||
|
||||
try {
|
||||
logger.write(MODULE_NAME, '[INFO] FileStorage -> getTextFile -> Entering Function.')
|
||||
|
||||
logger.write(MODULE_NAME, '[INFO] FileStorage -> getTextFile -> fileLocation: ' + fileLocation)
|
||||
let fileDoesNotExist = false
|
||||
|
||||
/* Here we actually write the file. */
|
||||
const fs = require('fs')
|
||||
fs.readFile(fileLocation, onFileRead)
|
||||
|
||||
function onFileRead(err, text) {
|
||||
let retryTimeToUse = FAST_RETRY_TIME_IN_MILISECONDS
|
||||
if (currentRetryGetTextFile > MAX_RETRY - 2) {
|
||||
retryTimeToUse = SLOW_RETRY_TIME_IN_MILISECONDS
|
||||
}
|
||||
if (err) {
|
||||
|
||||
if (err.code === 'ENOENT') { // since files are deleted before being replaced, it can happen that it does not exist and after a retry it does.
|
||||
if (noRetry === true) {
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> File does not exist. Not Retrying. ')
|
||||
let customResponse = {
|
||||
result: global.CUSTOM_FAIL_RESPONSE.result,
|
||||
message: 'File does not exist.'
|
||||
}
|
||||
callBackFunction(customResponse)
|
||||
return
|
||||
} else {
|
||||
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)
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Error reading file -> filePath = ' + filePath)
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Error reading file -> err = ' + err.stack)
|
||||
setTimeout(retry, retryTimeToUse)
|
||||
return
|
||||
}
|
||||
|
||||
if (text.toString() === "") {
|
||||
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())
|
||||
/* Choose path for either bots or data */
|
||||
let fileLocation
|
||||
if (filePath.indexOf("/bots/") > 0) {
|
||||
fileLocation = process.env.BOTS_PATH + '/' + filePath
|
||||
} else {
|
||||
fileLocation = process.env.STORAGE_PATH + '/' + filePath
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> Error writing file -> file = ' + fileLocation)
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> Error writing file -> err = ' + err.stack)
|
||||
retry()
|
||||
}
|
||||
try {
|
||||
|
||||
function retry() {
|
||||
//console.log(new Date(), ' Retry #: ' + currentRetryGetTextFile, fileLocation )
|
||||
if (currentRetryGetTextFile < MAX_RETRY) {
|
||||
currentRetryGetTextFile++
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> retry -> Will try to read the file again -> Retry #: ' + currentRetryGetTextFile)
|
||||
getTextFile(filePath, callBackFunction)
|
||||
} else {
|
||||
currentRetryGetTextFile = 0
|
||||
logger.write(MODULE_NAME, '[INFO] FileStorage -> getTextFile -> fileLocation: ' + fileLocation)
|
||||
|
||||
if (fileDoesNotExist === true) {
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> retry -> Max retries reached reading a file. File Not Found.')
|
||||
let customResponse = {
|
||||
result: global.CUSTOM_FAIL_RESPONSE.result,
|
||||
message: 'File does not exist.'
|
||||
/* Here we actually write the file. */
|
||||
const fs = require('fs')
|
||||
fs.readFile(fileLocation, onFileRead)
|
||||
|
||||
function onFileRead(err, text) {
|
||||
let retryTimeToUse = FAST_RETRY_TIME_IN_MILISECONDS
|
||||
if (currentRetryGetTextFile > MAX_RETRY - 2) {
|
||||
retryTimeToUse = SLOW_RETRY_TIME_IN_MILISECONDS
|
||||
}
|
||||
callBackFunction(customResponse)
|
||||
return
|
||||
if (err) {
|
||||
|
||||
if (err.code === 'ENOENT') { // since files are deleted before being replaced, it can happen that it does not exist and after a retry it does.
|
||||
if (noRetry === true) {
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> File does not exist. Not Retrying. ')
|
||||
let customResponse = {
|
||||
result: global.CUSTOM_FAIL_RESPONSE.result,
|
||||
message: 'File does not exist.'
|
||||
}
|
||||
callBackFunction(customResponse)
|
||||
return
|
||||
} else {
|
||||
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)
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Error reading file -> filePath = ' + filePath)
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> onFileRead -> Error reading file -> err = ' + err.stack)
|
||||
setTimeout(retry, retryTimeToUse)
|
||||
return
|
||||
}
|
||||
|
||||
if (text.toString() === "") {
|
||||
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())
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> Error writing file -> file = ' + fileLocation)
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> Error writing file -> err = ' + err.stack)
|
||||
retry()
|
||||
}
|
||||
|
||||
function retry() {
|
||||
//console.log(new Date(), ' Retry #: ' + currentRetryGetTextFile, fileLocation )
|
||||
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)
|
||||
} 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)
|
||||
return
|
||||
currentRetryGetTextFile = 0
|
||||
|
||||
if (fileDoesNotExist === true) {
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> getTextFile -> retry -> Max retries reached reading a file. File Not Found.')
|
||||
let customResponse = {
|
||||
result: global.CUSTOM_FAIL_RESPONSE.result,
|
||||
message: 'File does not exist.'
|
||||
}
|
||||
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)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -124,144 +128,161 @@ exports.newFileStorage = function newFileStorage(logger) {
|
||||
|
||||
function createTextFile(filePath, fileContent, callBackFunction) {
|
||||
|
||||
logger.write(MODULE_NAME, '[INFO] FileStorage -> createTextFile -> Entering Function.')
|
||||
let currentRetryWriteTextFile = 0
|
||||
|
||||
/* Choose path for either logs or data */
|
||||
let fileLocation
|
||||
if (filePath.indexOf("/Logs/") > 0) {
|
||||
fileLocation = process.env.LOG_PATH + '/' + filePath
|
||||
} else {
|
||||
fileLocation = process.env.STORAGE_PATH + '/' + filePath
|
||||
}
|
||||
recursiveCreateTextFile(filePath, fileContent, callBackFunction)
|
||||
|
||||
try {
|
||||
function recursiveCreateTextFile(filePath, fileContent, callBackFunction) {
|
||||
|
||||
logger.write(MODULE_NAME, '[INFO] FileStorage -> createTextFile -> fileLocation: ' + fileLocation)
|
||||
logger.write(MODULE_NAME, '[INFO] FileStorage -> createTextFile -> Entering Function.')
|
||||
|
||||
/* If necesary a folder or folders are created before writing the file to disk. */
|
||||
let directoryPath = fileLocation.substring(0, fileLocation.lastIndexOf('/') + 1);
|
||||
mkDirByPathSync(directoryPath)
|
||||
/* Choose path for either logs or data */
|
||||
let fileLocation
|
||||
if (filePath.indexOf("/Logs/") > 0) {
|
||||
fileLocation = process.env.LOG_PATH + '/' + filePath
|
||||
} else {
|
||||
fileLocation = process.env.STORAGE_PATH + '/' + filePath
|
||||
}
|
||||
|
||||
/*
|
||||
Here we write the file with a temporary name so as to avoid dirty read from other processes.
|
||||
Then we delete the original file, if exists, and finally we rename the temporary into the original name.
|
||||
*/
|
||||
const fs = require('fs')
|
||||
fs.writeFile(fileLocation + '.tmp', fileContent, onFileWritenn)
|
||||
try {
|
||||
|
||||
function onFileWritenn(err) {
|
||||
let retryTimeToUse = FAST_RETRY_TIME_IN_MILISECONDS
|
||||
if (currentRetryWriteTextFile > MAX_RETRY - 2) {
|
||||
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 -> err = ' + err.stack)
|
||||
setTimeout(retry, retryTimeToUse)
|
||||
} else {
|
||||
logger.write(MODULE_NAME, '[INFO] FileStorage -> createTextFile -> fileLocation: ' + fileLocation)
|
||||
|
||||
const fs = require('fs')
|
||||
fs.unlink(fileLocation, onUnlinked)
|
||||
/* If necesary a folder or folders are created before writing the file to disk. */
|
||||
let directoryPath = fileLocation.substring(0, fileLocation.lastIndexOf('/') + 1);
|
||||
mkDirByPathSync(directoryPath)
|
||||
|
||||
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 {
|
||||
/*
|
||||
Here we write the file with a temporary name so as to avoid dirty read from other processes.
|
||||
Then we delete the original file, if exists, and finally we rename the temporary into the original name.
|
||||
*/
|
||||
const fs = require('fs')
|
||||
fs.writeFile(fileLocation + '.tmp', fileContent, onFileWritenn)
|
||||
|
||||
const fs = require('fs')
|
||||
fs.rename(fileLocation + '.tmp', fileLocation, onRenamed)
|
||||
function onFileWritenn(err) {
|
||||
let retryTimeToUse = FAST_RETRY_TIME_IN_MILISECONDS
|
||||
if (currentRetryWriteTextFile > MAX_RETRY - 2) {
|
||||
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 -> err = ' + err.stack)
|
||||
setTimeout(retry, retryTimeToUse)
|
||||
} else {
|
||||
|
||||
function onRenamed(err) {
|
||||
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)
|
||||
setTimeout(retry, retryTimeToUse)
|
||||
} else {
|
||||
const fs = require('fs')
|
||||
fs.unlink(fileLocation, onUnlinked)
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE)
|
||||
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 {
|
||||
|
||||
const fs = require('fs')
|
||||
fs.rename(fileLocation + '.tmp', fileLocation, onRenamed)
|
||||
|
||||
function onRenamed(err) {
|
||||
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)
|
||||
setTimeout(retry, retryTimeToUse)
|
||||
} else {
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> Error writing file -> file = ' + fileLocation)
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> Error writing file -> err = ' + err.stack)
|
||||
retry()
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> Error writing file -> file = ' + fileLocation)
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> Error writing file -> err = ' + err.stack)
|
||||
retry()
|
||||
}
|
||||
|
||||
function retry() {
|
||||
if (currentRetryWriteTextFile < MAX_RETRY) {
|
||||
currentRetryWriteTextFile++
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> createTextFile -> retry -> Will try to write the file again -> Retry #: ' + currentRetryWriteTextFile)
|
||||
createTextFile(filePath, fileContent, callBackFunction)
|
||||
} else {
|
||||
currentRetryWriteTextFile = 0
|
||||
logger.write(MODULE_NAME, '[ERROR] FileStorage -> createTextFile -> retry -> Max retries reached writting a file. Giving up.')
|
||||
logger.write(MODULE_NAME, '[ERROR] FileStorage -> createTextFile -> retry -> file = ' + fileLocation)
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
|
||||
function retry() {
|
||||
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)
|
||||
} else {
|
||||
currentRetryWriteTextFile = 0
|
||||
logger.write(MODULE_NAME, '[ERROR] FileStorage -> createTextFile -> retry -> Max retries reached writting a file. Giving up.')
|
||||
logger.write(MODULE_NAME, '[ERROR] FileStorage -> createTextFile -> retry -> file = ' + fileLocation)
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function deleteTextFile(filePath, callBackFunction) {
|
||||
|
||||
logger.write(MODULE_NAME, '[INFO] FileStorage -> deleteTextFile -> Entering Function.')
|
||||
let currentRetryDeleteTextFile = 0
|
||||
|
||||
/* Choose path for either logs or data */
|
||||
let fileLocation
|
||||
if (filePath.indexOf("/Logs/") > 0) {
|
||||
fileLocation = process.env.LOG_PATH + '/' + filePath
|
||||
} else {
|
||||
fileLocation = process.env.STORAGE_PATH + '/' + filePath
|
||||
}
|
||||
recursiveDeleteTextFile(filePath, callBackFunction)
|
||||
|
||||
try {
|
||||
function recursiveDeleteTextFile(filePath, callBackFunction) {
|
||||
logger.write(MODULE_NAME, '[INFO] FileStorage -> deleteTextFile -> Entering Function.')
|
||||
|
||||
logger.write(MODULE_NAME, '[INFO] FileStorage -> deleteTextFile -> fileLocation: ' + fileLocation)
|
||||
/* Choose path for either logs or data */
|
||||
let fileLocation
|
||||
if (filePath.indexOf("/Logs/") > 0) {
|
||||
fileLocation = process.env.LOG_PATH + '/' + filePath
|
||||
} else {
|
||||
fileLocation = process.env.STORAGE_PATH + '/' + filePath
|
||||
}
|
||||
|
||||
const fs = require('fs')
|
||||
fs.unlink(fileLocation, onUnlinked)
|
||||
try {
|
||||
|
||||
function onUnlinked(err) {
|
||||
if (err) {
|
||||
if (callBackFunction !== undefined) {
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
|
||||
logger.write(MODULE_NAME, '[INFO] FileStorage -> deleteTextFile -> fileLocation: ' + fileLocation)
|
||||
|
||||
const fs = require('fs')
|
||||
fs.unlink(fileLocation, onUnlinked)
|
||||
|
||||
function onUnlinked(err) {
|
||||
let retryTimeToUse = FAST_RETRY_TIME_IN_MILISECONDS
|
||||
if (currentRetryDeleteTextFile > MAX_RETRY - 2) {
|
||||
retryTimeToUse = SLOW_RETRY_TIME_IN_MILISECONDS
|
||||
}
|
||||
if (err) {
|
||||
if (callBackFunction !== undefined) {
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
} else {
|
||||
setTimeout(retry, retryTimeToUse)
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> deleteTextFile -> Error writing file -> file = ' + fileLocation)
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> deleteTextFile -> Error writing file -> err = ' + err.stack)
|
||||
if (callBackFunction !== undefined) {
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
|
||||
function retry() {
|
||||
if (currentRetryDeleteTextFile < MAX_RETRY) {
|
||||
currentRetryDeleteTextFile++
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> deleteTextFile -> retry -> Will try to delete the file again -> Retry #: ' + currentRetryDeleteTextFile)
|
||||
recursiveDeleteTextFile(filePath, callBackFunction)
|
||||
} else {
|
||||
currentRetryDeleteTextFile = 0
|
||||
logger.write(MODULE_NAME, '[ERROR] FileStorage -> deleteTextFile -> retry -> Max retries reached deleting a file. Giving up.')
|
||||
logger.write(MODULE_NAME, '[ERROR] FileStorage -> deleteTextFile -> retry -> file = ' + fileLocation)
|
||||
if (callBackFunction !== undefined) {
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE)
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> deleteTextFile -> Error writing file -> file = ' + fileLocation)
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> deleteTextFile -> Error writing file -> err = ' + err.stack)
|
||||
if (callBackFunction !== undefined) {
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
|
||||
function retry() {
|
||||
if (currentRetryDeleteTextFile < MAX_RETRY) {
|
||||
currentRetryDeleteTextFile++
|
||||
logger.write(MODULE_NAME, '[WARN] FileStorage -> deleteTextFile -> retry -> Will try to delete the file again -> Retry #: ' + currentRetryDeleteTextFile)
|
||||
createTextFile(filePath, fileContent, callBackFunction)
|
||||
} else {
|
||||
currentRetryDeleteTextFile = 0
|
||||
logger.write(MODULE_NAME, '[ERROR] FileStorage -> deleteTextFile -> retry -> Max retries reached deleting a file. Giving up.')
|
||||
logger.write(MODULE_NAME, '[ERROR] FileStorage -> deleteTextFile -> retry -> file = ' + fileLocation)
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-10
@@ -332,9 +332,13 @@
|
||||
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimeFramesMarketFiles -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> text = " + text); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> processTimeFramesMarketFiles -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> err = " + err.message);
|
||||
callBackFunction(err);
|
||||
if (err.message === 'File does not exist.') {
|
||||
logger.write(MODULE_NAME, "[ERROR] The file " + filePath + '/' + fileName + ' does not exist and it is required to continue. This process will retry to read it in a while. In the meantime make yourself sure that the process that generates it has ran properly.');
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
} else {
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> processTimeFramesMarketFiles -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> err = " + err.message);
|
||||
callBackFunction(err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -660,7 +664,7 @@
|
||||
|
||||
if ((err.result === "Fail Because" && err.message === "File does not exist.") || err.code === 'The specified key does not exist.') {
|
||||
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> processTimeFramesDailyFiles -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> err = " + err.stack);
|
||||
logger.write(MODULE_NAME, "[ERROR] The file " + filePath + '/' + fileName + ' does not exist and it is required to continue. This process will retry to read it in a while. In the meantime make yourself sure that the process that generates it has ran properly.');
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
@@ -721,12 +725,7 @@
|
||||
|
||||
if ((err.result === "Fail Because" && err.message === "File does not exist.") || err.code === 'The specified key does not exist.') {
|
||||
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> processTimeFramesDailyFiles -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> Fail Because -> err = " + err.message);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> processTimeFramesDailyFiles -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> filePath = " + filePath);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> processTimeFramesDailyFiles -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> fileName = " + fileName);
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> processTimeFramesDailyFiles -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> You are trying to use data that does not exist. ");
|
||||
logger.write(MODULE_NAME, "[ERROR] start -> processTimeFramesDailyFiles -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> Check that your Datasets building processes are running well. ");
|
||||
|
||||
logger.write(MODULE_NAME, "[ERROR] The file " + filePath + '/' + fileName + ' does not exist and it is required to continue. This process will retry to read it in a while. In the meantime make yourself sure that the process that generates it has ran properly.');
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
+25
-141
@@ -187,13 +187,6 @@
|
||||
|
||||
/* Set all default values */
|
||||
bot.VALUES_TO_USE = {
|
||||
baseAsset: "BTC",
|
||||
initialBalanceA: 0.001,
|
||||
initialBalanceB: 0,
|
||||
minimumBalanceA: 0.0005,
|
||||
minimumBalanceB: 0,
|
||||
maximumBalanceA: 0.002,
|
||||
maximumBalanceB: 0,
|
||||
slippage: {
|
||||
positionRate: 0,
|
||||
stopLoss: 0,
|
||||
@@ -238,132 +231,6 @@
|
||||
|
||||
if (tradingSystem !== undefined) {
|
||||
|
||||
/* Applying Trading System Level Parameters */
|
||||
if (tradingSystem.parameters !== undefined) {
|
||||
|
||||
/* Base Asset and Initial Balances. */
|
||||
{
|
||||
if (tradingSystem.parameters.baseAsset !== undefined) {
|
||||
if (tradingSystem.parameters.baseAsset.referenceParent !== undefined) {
|
||||
if (tradingSystem.parameters.baseAsset.referenceParent.referenceParent !== undefined) {
|
||||
|
||||
let code = tradingSystem.parameters.baseAsset.referenceParent.referenceParent.code
|
||||
|
||||
if (code.codeName !== undefined) {
|
||||
bot.VALUES_TO_USE.baseAsset = code.codeName;
|
||||
}
|
||||
|
||||
code = tradingSystem.parameters.baseAsset.code
|
||||
|
||||
if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) {
|
||||
if (code.initialBalance !== undefined) {
|
||||
bot.VALUES_TO_USE.initialBalanceA = code.initialBalance;
|
||||
bot.VALUES_TO_USE.initialBalanceB = 0
|
||||
}
|
||||
if (code.minimumBalance !== undefined) {
|
||||
bot.VALUES_TO_USE.minimumBalanceA = code.minimumBalance;
|
||||
bot.VALUES_TO_USE.minimumBalanceB = 0
|
||||
}
|
||||
if (code.maximumBalance !== undefined) {
|
||||
bot.VALUES_TO_USE.maximumBalanceA = code.maximumBalance;
|
||||
bot.VALUES_TO_USE.maximumBalanceB = 0
|
||||
}
|
||||
} else {
|
||||
if (code.initialBalance !== undefined) {
|
||||
bot.VALUES_TO_USE.initialBalanceB = code.initialBalance;
|
||||
bot.VALUES_TO_USE.initialBalanceA = 0
|
||||
}
|
||||
if (code.minimumBalance !== undefined) {
|
||||
bot.VALUES_TO_USE.minimumBalanceB = code.minimumBalance;
|
||||
bot.VALUES_TO_USE.minimumBalanceA = 0
|
||||
}
|
||||
if (code.maximumBalance !== undefined) {
|
||||
bot.VALUES_TO_USE.maximumBalanceB = code.maximumBalance;
|
||||
bot.VALUES_TO_USE.maximumBalanceA = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Quoted Asset */
|
||||
{
|
||||
if (tradingSystem.parameters.quotedAsset !== undefined) {
|
||||
if (tradingSystem.parameters.quotedAsset.referenceParent !== undefined) {
|
||||
if (tradingSystem.parameters.quotedAsset.referenceParent.referenceParent !== undefined) {
|
||||
|
||||
let code = tradingSystem.parameters.quotedAsset.referenceParent.referenceParent.code
|
||||
|
||||
if (code.codeName !== undefined) {
|
||||
bot.VALUES_TO_USE.quotedAsset = code.codeName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Time Frame */
|
||||
if (tradingSystem.parameters.timeFrame !== undefined) {
|
||||
bot.VALUES_TO_USE.timeFrame = tradingSystem.parameters.timeFrame.code.value
|
||||
}
|
||||
|
||||
/* Slippage */
|
||||
if (tradingSystem.parameters.slippage !== undefined) {
|
||||
if (tradingSystem.parameters.slippage.code !== undefined) {
|
||||
|
||||
let code = tradingSystem.parameters.slippage.code
|
||||
|
||||
if (code.positionRate !== undefined) {
|
||||
bot.VALUES_TO_USE.slippage.positionRate = code.positionRate
|
||||
}
|
||||
if (code.stopLoss !== undefined) {
|
||||
bot.VALUES_TO_USE.slippage.stopLoss = code.stopLoss
|
||||
}
|
||||
if (code.takeProfit !== undefined) {
|
||||
bot.VALUES_TO_USE.slippage.takeProfit = code.takeProfit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Fee Structure */
|
||||
if (tradingSystem.parameters.feeStructure !== undefined) {
|
||||
if (tradingSystem.parameters.feeStructure.code !== undefined) {
|
||||
|
||||
let code = tradingSystem.parameters.feeStructure.code
|
||||
|
||||
if (code.maker !== undefined) {
|
||||
bot.VALUES_TO_USE.feeStructure.maker = code.maker
|
||||
}
|
||||
if (code.taker !== undefined) {
|
||||
bot.VALUES_TO_USE.feeStructure.taker = code.taker
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Time Range */
|
||||
if (tradingSystem.parameters.timeRange !== undefined) {
|
||||
if (tradingSystem.parameters.timeRange.code !== undefined) {
|
||||
|
||||
let code = tradingSystem.parameters.timeRange.code
|
||||
if (code.initialDatetime !== undefined) {
|
||||
if (isNaN(Date.parse(code.initialDatetime)) === true) {
|
||||
parentLogger.write(MODULE_NAME, "[WARN] initialize -> runSession -> setValuesToUse -> Cannot use initialDatatime provided at Trading System Parameters because it is not a valid Date.");
|
||||
} else {
|
||||
bot.VALUES_TO_USE.timeRange.initialDatetime = new Date(code.initialDatetime)
|
||||
}
|
||||
}
|
||||
if (code.finalDatetime !== undefined) {
|
||||
if (isNaN(Date.parse(code.finalDatetime)) === true) {
|
||||
parentLogger.write(MODULE_NAME, "[WARN] initialize -> runSession -> setValuesToUse -> Cannot use finalDatetime provided at Trading System Parameters because it is not a valid Date.");
|
||||
} else {
|
||||
bot.VALUES_TO_USE.timeRange.finalDatetime = new Date(code.finalDatetime)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Applying Session Level Parameters */
|
||||
if (bot.SESSION !== undefined) {
|
||||
if (bot.SESSION.parameters !== undefined) {
|
||||
@@ -409,6 +276,23 @@
|
||||
bot.VALUES_TO_USE.maximumBalanceA = 0
|
||||
}
|
||||
}
|
||||
|
||||
/* Solve when values are missing. */
|
||||
if (bot.VALUES_TO_USE.minimumBalanceA === undefined) {
|
||||
bot.VALUES_TO_USE.minimumBalanceA = 0
|
||||
}
|
||||
|
||||
if (bot.VALUES_TO_USE.minimumBalanceB === undefined) {
|
||||
bot.VALUES_TO_USE.minimumBalanceB = 0
|
||||
}
|
||||
|
||||
if (bot.VALUES_TO_USE.maximumBalanceA === undefined) {
|
||||
bot.VALUES_TO_USE.maximumBalanceA = 10000000000000000
|
||||
}
|
||||
|
||||
if (bot.VALUES_TO_USE.maximumBalanceB === undefined) {
|
||||
bot.VALUES_TO_USE.maximumBalanceB = 10000000000000000
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -512,16 +396,16 @@
|
||||
for (let i = 0; i < bot.SESSION.socialBots.bots.length; i++) {
|
||||
let socialBot = bot.SESSION.socialBots.bots[i]
|
||||
try {
|
||||
let code = JSON.parse(announcement.code)
|
||||
if (socialBot.id === announcement.referenceParent.id) {
|
||||
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))
|
||||
} 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))
|
||||
}
|
||||
let code = announcement.code
|
||||
|
||||
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))
|
||||
} 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))
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
parentLogger.write(MODULE_NAME, "[WARN] initialize -> setUpSocialBots -> announce -> err = " + err.stack);
|
||||
}
|
||||
|
||||
+8
-4
@@ -356,7 +356,8 @@
|
||||
record.status + "," +
|
||||
record.number + "," +
|
||||
record.beginRate + "," +
|
||||
record.endRate + "]";
|
||||
record.endRate + "," +
|
||||
'"' + record.triggerOnSituation + '"' + "]";
|
||||
|
||||
if (separator === "") { separator = ","; }
|
||||
|
||||
@@ -428,7 +429,8 @@
|
||||
record.lastTradeROI + "," +
|
||||
record.beginRate + "," +
|
||||
record.endRate + "," +
|
||||
record.exitType + "]";
|
||||
record.exitType + "," +
|
||||
'"' + record.takePositionSituation + '"' + "]";
|
||||
|
||||
if (separator === "") { separator = ","; }
|
||||
|
||||
@@ -816,7 +818,8 @@
|
||||
record.status + "," +
|
||||
record.number + "," +
|
||||
record.beginRate + "," +
|
||||
record.endRate + "]";
|
||||
record.endRate + "," +
|
||||
'"' + record.triggerOnSituation + '"' + "]";
|
||||
|
||||
if (separator === "") { separator = ","; }
|
||||
|
||||
@@ -894,7 +897,8 @@
|
||||
record.lastTradeROI + "," +
|
||||
record.beginRate + "," +
|
||||
record.endRate + "," +
|
||||
record.exitType + "]";
|
||||
record.exitType + "," +
|
||||
'"' + record.takePositionSituation + '"' + "]";
|
||||
|
||||
if (separator === "") { separator = ","; }
|
||||
|
||||
|
||||
+182
-139
@@ -14,21 +14,9 @@
|
||||
|
||||
let utilities = UTILITIES.newCloudUtilities(bot, logger);
|
||||
|
||||
let percentageBandwidthAt = {}
|
||||
let bollingerBandsAt = {}
|
||||
let bollingerChannelsAt = {}
|
||||
let bollingerSubChannelsAt = {}
|
||||
let candlesAt = {}
|
||||
|
||||
|
||||
return thisObject;
|
||||
|
||||
function finalize() {
|
||||
percentageBandwidthAt = undefined
|
||||
bollingerBandsAt = undefined
|
||||
bollingerChannelsAt = undefined
|
||||
bollingerSubChannelsAt = undefined
|
||||
candlesAt = undefined
|
||||
thisObject = undefined
|
||||
}
|
||||
|
||||
@@ -141,7 +129,8 @@
|
||||
status: 0,
|
||||
number: 0,
|
||||
beginRate: 0,
|
||||
endRate: 0
|
||||
endRate: 0,
|
||||
triggerOnSituation: ''
|
||||
}
|
||||
|
||||
let currentTrade = {
|
||||
@@ -151,7 +140,8 @@
|
||||
profit: 0,
|
||||
exitType: 0,
|
||||
beginRate: 0,
|
||||
endRate: 0
|
||||
endRate: 0,
|
||||
takePositionSituation: ''
|
||||
}
|
||||
|
||||
let balanceBaseAsset = bot.VALUES_TO_USE.initialBalanceA;
|
||||
@@ -183,6 +173,10 @@
|
||||
let orderId = 0;
|
||||
let messageId = 0;
|
||||
|
||||
/* Allowing these to be accesible at formulas */
|
||||
baseAsset = bot.VALUES_TO_USE.baseAsset
|
||||
quotedAsset = bot.VALUES_TO_USE.quotedAsset
|
||||
|
||||
let yesterday = {};
|
||||
|
||||
/* Initialization */
|
||||
@@ -211,7 +205,8 @@
|
||||
status: 0,
|
||||
number: 0,
|
||||
beginRate: 0,
|
||||
endRate: 0
|
||||
endRate: 0,
|
||||
triggerOnSituation: ''
|
||||
}
|
||||
|
||||
yesterday.currentTrade = {
|
||||
@@ -221,7 +216,8 @@
|
||||
profit: 0,
|
||||
exitType: 0,
|
||||
beginRate: 0,
|
||||
endRate: 0
|
||||
endRate: 0,
|
||||
takePositionSituation: ''
|
||||
}
|
||||
|
||||
yesterday.balanceBaseAsset = balanceBaseAsset;
|
||||
@@ -279,7 +275,8 @@
|
||||
status: 0,
|
||||
number: 0,
|
||||
beginRate: 0,
|
||||
endRate: 0
|
||||
endRate: 0,
|
||||
triggerOnSituation: ''
|
||||
}
|
||||
|
||||
interExecutionMemory.currentTrade = {
|
||||
@@ -289,7 +286,8 @@
|
||||
profit: 0,
|
||||
exitType: 0,
|
||||
beginRate: 0,
|
||||
endRate: 0
|
||||
endRate: 0,
|
||||
takePositionSituation: ''
|
||||
}
|
||||
|
||||
interExecutionMemory.balanceBaseAsset = balanceBaseAsset;
|
||||
@@ -349,7 +347,8 @@
|
||||
status: interExecutionMemory.currentStrategy.status,
|
||||
number: interExecutionMemory.currentStrategy.number,
|
||||
beginRate: interExecutionMemory.currentStrategy.beginRate,
|
||||
endRate: interExecutionMemory.currentStrategy.endRate
|
||||
endRate: interExecutionMemory.currentStrategy.endRate,
|
||||
triggerOnSituation: interExecutionMemory.currentStrategy.triggerOnSituation
|
||||
}
|
||||
|
||||
currentTrade = {
|
||||
@@ -359,7 +358,8 @@
|
||||
profit: interExecutionMemory.currentTrade.profit,
|
||||
exitType: interExecutionMemory.currentTrade.exitType,
|
||||
beginRate: interExecutionMemory.currentTrade.beginRate,
|
||||
endRate: interExecutionMemory.currentTrade.endRate
|
||||
endRate: interExecutionMemory.currentTrade.endRate,
|
||||
takePositionSituation: interExecutionMemory.currentTrade.takePositionSituation
|
||||
}
|
||||
|
||||
if (currentDay) {
|
||||
@@ -422,7 +422,8 @@
|
||||
status: currentStrategy.status,
|
||||
number: currentStrategy.number,
|
||||
beginRate: currentStrategy.beginRate,
|
||||
endRate: currentStrategy.endRate
|
||||
endRate: currentStrategy.endRate,
|
||||
triggerOnSituation: currentStrategy.triggerOnSituation
|
||||
}
|
||||
|
||||
yesterday.currentTrade = {
|
||||
@@ -432,7 +433,8 @@
|
||||
profit: currentTrade.profit,
|
||||
exitType: currentTrade.exitType,
|
||||
beginRate: currentTrade.beginRate,
|
||||
endRate: currentTrade.endRate
|
||||
endRate: currentTrade.endRate,
|
||||
takePositionSituation: currentTrade.takePositionSituation
|
||||
}
|
||||
|
||||
yesterday.lastTradeProfitLoss = lastTradeProfitLoss;
|
||||
@@ -570,9 +572,19 @@
|
||||
let processingDate = loopingDay.getUTCFullYear() + '-' + utilities.pad(loopingDay.getUTCMonth() + 1, 2) + '-' + utilities.pad(loopingDay.getUTCDate(), 2);
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Simulation " + bot.sessionKey + " Loop # " + currentCandleIndex + " @ " + processingDate) }
|
||||
console.log("Trading-Engine -> " + MODULE_NAME + " -> runSimulation -> loop -> Simulation " + bot.sessionKey + " Loop # " + currentCandleIndex + " @ " + processingDate)
|
||||
|
||||
bot.sessionHeartBeat(processingDate) // tell the world we are alive and doing well
|
||||
/* Telling the world we are alive and doing well */
|
||||
let fromDate = new Date(bot.VALUES_TO_USE.timeRange.initialDatetime.valueOf())
|
||||
let lastDate = new Date(bot.VALUES_TO_USE.timeRange.finalDatetime.valueOf())
|
||||
|
||||
let currentDateString = loopingDay.getUTCFullYear() + '-' + utilities.pad(loopingDay.getUTCMonth() + 1, 2) + '-' + utilities.pad(loopingDay.getUTCDate(), 2);
|
||||
let currentDate = new Date(loopingDay)
|
||||
let percentage = global.getPercentage(fromDate, currentDate, lastDate)
|
||||
bot.processHeartBeat(currentDateString, percentage)
|
||||
|
||||
if (global.areEqualDates(currentDate, new Date()) === false) {
|
||||
logger.newInternalLoop(bot.codeName, bot.process, currentDate, percentage);
|
||||
}
|
||||
}
|
||||
previousLoopingDay = loopingDay.valueOf()
|
||||
|
||||
@@ -706,7 +718,7 @@
|
||||
if (openStage !== undefined) {
|
||||
|
||||
/* Default Values*/
|
||||
if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) {
|
||||
if (baseAsset === bot.market.baseAsset) {
|
||||
positionSize = balanceBaseAsset;
|
||||
positionRate = candle.close;
|
||||
} else {
|
||||
@@ -729,13 +741,13 @@
|
||||
initialDefinition.positionSize.formula.error = err.message
|
||||
}
|
||||
if (isNaN(positionSize)) {
|
||||
if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) {
|
||||
if (baseAsset === bot.market.baseAsset) {
|
||||
positionSize = balanceBaseAsset;
|
||||
} else {
|
||||
positionSize = balanceQuotedAsset;
|
||||
}
|
||||
} else {
|
||||
if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) {
|
||||
if (baseAsset === bot.market.baseAsset) {
|
||||
if (positionSize > balanceBaseAsset) { positionSize = balanceBaseAsset }
|
||||
} else {
|
||||
if (positionSize > balanceQuotedAsset) { positionSize = balanceQuotedAsset }
|
||||
@@ -756,7 +768,7 @@
|
||||
initialDefinition.positionRate.formula.error = err.message
|
||||
}
|
||||
if (isNaN(positionRate)) {
|
||||
if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) {
|
||||
if (baseAsset === bot.market.baseAsset) {
|
||||
positionRate = candle.close;
|
||||
} else {
|
||||
positionRate = candle.close;
|
||||
@@ -1093,7 +1105,7 @@
|
||||
let maximumBalance
|
||||
let balance
|
||||
|
||||
if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) {
|
||||
if (baseAsset === bot.market.baseAsset) {
|
||||
balance = balanceBaseAsset
|
||||
minimumBalance = bot.VALUES_TO_USE.minimumBalanceA
|
||||
maximumBalance = bot.VALUES_TO_USE.maximumBalanceA
|
||||
@@ -1102,100 +1114,101 @@
|
||||
minimumBalance = bot.VALUES_TO_USE.minimumBalanceB
|
||||
maximumBalance = bot.VALUES_TO_USE.maximumBalanceB
|
||||
}
|
||||
|
||||
if (minimumBalance === undefined) {
|
||||
minimumBalance = 0
|
||||
|
||||
let stopRunningDate = new Date(candle.begin)
|
||||
if (balance <= minimumBalance) {
|
||||
tradingSystem.error = "Min Balance @ " + stopRunningDate.toLocaleString()
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> " + tradingSystem.error ); }
|
||||
afterLoop()
|
||||
return
|
||||
}
|
||||
|
||||
if (maximumBalance === undefined) {
|
||||
maximumBalance = 10000000000000000
|
||||
if (balance >= maximumBalance) {
|
||||
tradingSystem.error = "Max Balance @ " + stopRunningDate.toLocaleString()
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> " + tradingSystem.error); }
|
||||
afterLoop()
|
||||
return
|
||||
}
|
||||
|
||||
if (balance > minimumBalance && balance < maximumBalance) {
|
||||
|
||||
/*
|
||||
Here we need to pick a strategy, or if there is not suitable strategy for the current
|
||||
market conditions, we pass until the next period.
|
||||
/*
|
||||
Here we need to pick a strategy, or if there is not suitable strategy for the current
|
||||
market conditions, we pass until the next period.
|
||||
|
||||
To pick a new strategy we will evaluate what we call the trigger on. Once we enter
|
||||
into one strategy, we will ignore market conditions for others. However there is also
|
||||
a strategy trigger off which can be hit before taking a position. If hit, we would
|
||||
be outside a strategy again and looking for the condition to enter all over again.
|
||||
To pick a new strategy we will evaluate what we call the trigger on. Once we enter
|
||||
into one strategy, we will ignore market conditions for others. However there is also
|
||||
a strategy trigger off which can be hit before taking a position. If hit, we would
|
||||
be outside a strategy again and looking for the condition to enter all over again.
|
||||
|
||||
*/
|
||||
*/
|
||||
|
||||
for (let j = 0; j < tradingSystem.strategies.length; j++) {
|
||||
for (let j = 0; j < tradingSystem.strategies.length; j++) {
|
||||
|
||||
let strategy = tradingSystem.strategies[j];
|
||||
let strategy = tradingSystem.strategies[j];
|
||||
|
||||
let triggerStage = strategy.triggerStage
|
||||
let triggerStage = strategy.triggerStage
|
||||
|
||||
if (triggerStage !== undefined) {
|
||||
if (triggerStage !== undefined) {
|
||||
|
||||
if (triggerStage.triggerOn !== undefined) {
|
||||
if (triggerStage.triggerOn !== undefined) {
|
||||
|
||||
for (let k = 0; k < triggerStage.triggerOn.situations.length; k++) {
|
||||
for (let k = 0; k < triggerStage.triggerOn.situations.length; k++) {
|
||||
|
||||
let situation = triggerStage.triggerOn.situations[k];
|
||||
let passed = true;
|
||||
let situation = triggerStage.triggerOn.situations[k];
|
||||
let passed = true;
|
||||
|
||||
for (let m = 0; m < situation.conditions.length; m++) {
|
||||
for (let m = 0; m < situation.conditions.length; m++) {
|
||||
|
||||
let condition = situation.conditions[m];
|
||||
let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m;
|
||||
let condition = situation.conditions[m];
|
||||
let key = j + '-' + 'triggerStage' + '-' + 'triggerOn' + '-' + k + '-' + m;
|
||||
|
||||
let value = false
|
||||
if (conditions.get(key) !== undefined) {
|
||||
value = conditions.get(key).value;
|
||||
}
|
||||
|
||||
if (value === false) { passed = false; }
|
||||
let value = false
|
||||
if (conditions.get(key) !== undefined) {
|
||||
value = conditions.get(key).value;
|
||||
}
|
||||
|
||||
if (passed) {
|
||||
if (value === false) { passed = false; }
|
||||
}
|
||||
|
||||
strategyStage = 'Trigger Stage';
|
||||
currentStrategyIndex = j;
|
||||
currentStrategy.begin = candle.begin;
|
||||
currentStrategy.beginRate = candle.min;
|
||||
currentStrategy.endRate = candle.min; // In case the strategy does not get exited
|
||||
if (passed) {
|
||||
|
||||
if (processingDailyFiles) {
|
||||
if (positionedAtYesterday) {
|
||||
yesterday.strategyStage = strategyStage;
|
||||
yesterday.currentStrategyIndex = currentStrategyIndex;
|
||||
yesterday.currentStrategy.begin = currentStrategy.begin;
|
||||
yesterday.currentStrategy.beginRate = currentStrategy.beginRate;
|
||||
yesterday.currentStrategy.endRate = currentStrategy.endRate;
|
||||
}
|
||||
strategyStage = 'Trigger Stage';
|
||||
checkAnnouncements(triggerStage)
|
||||
|
||||
currentStrategyIndex = j;
|
||||
currentStrategy.begin = candle.begin;
|
||||
currentStrategy.beginRate = candle.min;
|
||||
currentStrategy.endRate = candle.min; // In case the strategy does not get exited
|
||||
currentStrategy.triggerOnSituation = situation.name
|
||||
|
||||
if (processingDailyFiles) {
|
||||
if (positionedAtYesterday) {
|
||||
yesterday.strategyStage = strategyStage;
|
||||
yesterday.currentStrategyIndex = currentStrategyIndex;
|
||||
yesterday.currentStrategy.begin = currentStrategy.begin;
|
||||
yesterday.currentStrategy.beginRate = currentStrategy.beginRate;
|
||||
yesterday.currentStrategy.endRate = currentStrategy.endRate;
|
||||
yesterday.currentStrategy.triggerOnSituation = currentStrategy.triggerOnSituation;
|
||||
}
|
||||
|
||||
distanceToLast.triggerOn = 1;
|
||||
|
||||
if (processingDailyFiles) {
|
||||
if (positionedAtYesterday) {
|
||||
yesterday.distanceToLast.triggerOn = distanceToLast.triggerOn
|
||||
}
|
||||
}
|
||||
|
||||
checkAnnouncements(triggerStage.triggerOn)
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Switching to Trigger Stage because conditions at Trigger On Event were met."); }
|
||||
break;
|
||||
}
|
||||
|
||||
distanceToLast.triggerOn = 1;
|
||||
|
||||
if (processingDailyFiles) {
|
||||
if (positionedAtYesterday) {
|
||||
yesterday.distanceToLast.triggerOn = distanceToLast.triggerOn
|
||||
}
|
||||
}
|
||||
|
||||
checkAnnouncements(triggerStage.triggerOn)
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Switching to Trigger Stage because conditions at Trigger On Event were met."); }
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let stopRunningDate = new Date(candle.begin)
|
||||
if (balance <= minimumBalance) {
|
||||
tradingSystem.error = "Min Balance @ " + stopRunningDate.toLocaleString()
|
||||
}
|
||||
if (balance >= maximumBalance) {
|
||||
tradingSystem.error = "Max Balance @ " + stopRunningDate.toLocaleString()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Trigger Off Condition */
|
||||
@@ -1299,6 +1312,8 @@
|
||||
type = '"Take Position"';
|
||||
|
||||
strategyStage = 'Open Stage';
|
||||
checkAnnouncements(strategy.openStage)
|
||||
|
||||
stopLossStage = 'Open Stage';
|
||||
takeProfitStage = 'Open Stage';
|
||||
stopLossPhase = 0;
|
||||
@@ -1315,7 +1330,8 @@
|
||||
}
|
||||
|
||||
takePositionNow = true
|
||||
|
||||
currentTrade.takePositionSituation = situation.name
|
||||
|
||||
checkAnnouncements(triggerStage.takePosition)
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Conditions at the Take Position Event were met."); }
|
||||
@@ -1396,7 +1412,10 @@
|
||||
|
||||
stopLossPhase++;
|
||||
stopLossStage = 'Manage Stage'
|
||||
if (takeProfitPhase > 0) { strategyStage = 'Manage Stage' }
|
||||
if (takeProfitPhase > 0) {
|
||||
strategyStage = 'Manage Stage'
|
||||
checkAnnouncements(manageStage, 'Take Profit')
|
||||
}
|
||||
|
||||
if (processingDailyFiles) {
|
||||
if (positionedAtYesterday) {
|
||||
@@ -1501,6 +1520,7 @@
|
||||
|
||||
if (parentNode !== undefined) {
|
||||
let phase = parentNode.takeProfit.phases[p];
|
||||
if (phase === undefined) {return} // trying to jump to a phase that does not exists.
|
||||
|
||||
let nextPhaseEvent = phase.nextPhaseEvent;
|
||||
if (nextPhaseEvent !== undefined) {
|
||||
@@ -1527,7 +1547,10 @@
|
||||
|
||||
takeProfitPhase++;
|
||||
takeProfitStage = 'Manage Stage'
|
||||
if (stopLossPhase > 0) { strategyStage = 'Manage Stage' }
|
||||
if (stopLossPhase > 0) {
|
||||
strategyStage = 'Manage Stage'
|
||||
checkAnnouncements(manageStage, 'Stop')
|
||||
}
|
||||
|
||||
if (processingDailyFiles) {
|
||||
if (positionedAtYesterday) {
|
||||
@@ -1683,7 +1706,7 @@
|
||||
|
||||
/* Stop Loss condition: Here we verify if the Stop Loss was hitted or not. */
|
||||
|
||||
if ((bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset && candle.max >= stopLoss) || (bot.VALUES_TO_USE.baseAsset !== bot.market.baseAsset && candle.min <= stopLoss)) {
|
||||
if ((baseAsset === bot.market.baseAsset && candle.max >= stopLoss) || (baseAsset !== bot.market.baseAsset && candle.min <= stopLoss)) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Stop Loss was hit."); }
|
||||
/*
|
||||
@@ -1693,7 +1716,7 @@
|
||||
If we take the stop loss value at those situation would be a huge distortion of facts.
|
||||
*/
|
||||
|
||||
if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) {
|
||||
if (baseAsset === bot.market.baseAsset) {
|
||||
if (stopLoss < candle.min) {
|
||||
stopLoss = candle.min
|
||||
if (processingDailyFiles) {
|
||||
@@ -1718,7 +1741,7 @@
|
||||
/* Apply the Slippage */
|
||||
let slippageAmount = slippedStopLoss * bot.VALUES_TO_USE.slippage.stopLoss / 100
|
||||
|
||||
if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) {
|
||||
if (baseAsset === bot.market.baseAsset) {
|
||||
slippedStopLoss = slippedStopLoss + slippageAmount
|
||||
} else {
|
||||
slippedStopLoss = slippedStopLoss - slippageAmount
|
||||
@@ -1729,6 +1752,8 @@
|
||||
marketRate = closeRate;
|
||||
type = '"Close@StopLoss"';
|
||||
strategyStage = 'Close Stage';
|
||||
checkAnnouncements(strategy.closeStage, 'Stop')
|
||||
|
||||
stopLossStage = 'No Stage';
|
||||
takeProfitStage = 'No Stage';
|
||||
currentTrade.end = candle.end;
|
||||
@@ -1753,7 +1778,7 @@
|
||||
|
||||
/* Take Profit condition: Here we verify if the Take Profit was hit or not. */
|
||||
|
||||
if ((bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset && candle.min <= takeProfit) || (bot.VALUES_TO_USE.baseAsset !== bot.market.baseAsset && candle.max >= takeProfit)) {
|
||||
if ((baseAsset === bot.market.baseAsset && candle.min <= takeProfit) || (baseAsset !== bot.market.baseAsset && candle.max >= takeProfit)) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> loop -> Take Profit was hit."); }
|
||||
/*
|
||||
@@ -1763,7 +1788,7 @@
|
||||
If we take the stop loss value at those situation would be a huge distortion of facts.
|
||||
*/
|
||||
|
||||
if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) {
|
||||
if (baseAsset === bot.market.baseAsset) {
|
||||
if (takeProfit > candle.max) {
|
||||
takeProfit = candle.max
|
||||
if (processingDailyFiles) {
|
||||
@@ -1787,7 +1812,7 @@
|
||||
/* Apply the Slippage */
|
||||
let slippageAmount = slippedTakeProfit * bot.VALUES_TO_USE.slippage.takeProfit / 100
|
||||
|
||||
if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) {
|
||||
if (baseAsset === bot.market.baseAsset) {
|
||||
slippedTakeProfit = slippedTakeProfit + slippageAmount
|
||||
} else {
|
||||
slippedTakeProfit = slippedTakeProfit - slippageAmount
|
||||
@@ -1798,6 +1823,8 @@
|
||||
marketRate = closeRate;
|
||||
type = '"Close@TakeProfit"';
|
||||
strategyStage = 'Close Stage';
|
||||
checkAnnouncements(strategy.closeStage, 'Take Profit')
|
||||
|
||||
stopLossStage = 'No Stage';
|
||||
takeProfitStage = 'No Stage';
|
||||
|
||||
@@ -1848,7 +1875,7 @@
|
||||
/* We take what was calculated at the formula and apply the slippage. */
|
||||
let slippageAmount = tradePositionRate * bot.VALUES_TO_USE.slippage.positionRate / 100
|
||||
|
||||
if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) {
|
||||
if (baseAsset === bot.market.baseAsset) {
|
||||
tradePositionRate = tradePositionRate - slippageAmount
|
||||
} else {
|
||||
tradePositionRate = tradePositionRate + slippageAmount
|
||||
@@ -1976,7 +2003,7 @@
|
||||
let orderSide
|
||||
|
||||
|
||||
if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) {
|
||||
if (baseAsset === bot.market.baseAsset) {
|
||||
orderSide = "sell"
|
||||
|
||||
orderPrice = tradePositionRate - 100 // This is going to be ingnored at the Exchange API for now since we only put market orders.
|
||||
@@ -2070,7 +2097,7 @@
|
||||
|
||||
let feePaid = 0
|
||||
|
||||
if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) {
|
||||
if (baseAsset === bot.market.baseAsset) {
|
||||
|
||||
feePaid = tradePositionSize * tradePositionRate * bot.VALUES_TO_USE.feeStructure.taker / 100
|
||||
|
||||
@@ -2182,7 +2209,7 @@
|
||||
let amountB
|
||||
let orderSide
|
||||
|
||||
if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) {
|
||||
if (baseAsset === bot.market.baseAsset) {
|
||||
orderSide = "buy"
|
||||
|
||||
orderPrice = ticker.last + 100; // This is provisional and totally arbitrary, until we have a formula on the designer that defines this stuff.
|
||||
@@ -2264,7 +2291,7 @@
|
||||
|
||||
let feePaid = 0
|
||||
|
||||
if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) {
|
||||
if (baseAsset === bot.market.baseAsset) {
|
||||
strategy.positionSize = balanceQuotedAsset / closeRate;
|
||||
strategy.positionRate = closeRate;
|
||||
|
||||
@@ -2290,7 +2317,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) {
|
||||
if (baseAsset === bot.market.baseAsset) {
|
||||
lastTradeProfitLoss = balanceBaseAsset - previousBalanceBaseAsset;
|
||||
lastTradeROI = lastTradeProfitLoss * 100 / tradePositionSize;
|
||||
if (isNaN(lastTradeROI)) { lastTradeROI = 0; }
|
||||
@@ -2337,7 +2364,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) {
|
||||
if (baseAsset === bot.market.baseAsset) {
|
||||
ROI = (bot.VALUES_TO_USE.initialBalanceA + profit) / bot.VALUES_TO_USE.initialBalanceA - 1;
|
||||
hitRatio = hits / roundtrips;
|
||||
anualizedRateOfReturn = ROI / days * 365;
|
||||
@@ -2495,8 +2522,8 @@
|
||||
balanceQuotedAsset = Number.MAX_SAFE_INTEGER
|
||||
}
|
||||
|
||||
let quotedBaseAsset = '"' + bot.VALUES_TO_USE.baseAsset + '"'
|
||||
let quotedQuotedAsset = '"' + bot.VALUES_TO_USE.quotedAsset + '"'
|
||||
let quotedBaseAsset = '"' + baseAsset + '"'
|
||||
let quotedQuotedAsset = '"' + quotedAsset + '"'
|
||||
|
||||
simulationRecord = {
|
||||
begin: candle.begin,
|
||||
@@ -2578,7 +2605,8 @@
|
||||
status: 0,
|
||||
number: 0,
|
||||
beginRate: 0,
|
||||
endRate: 0
|
||||
endRate: 0,
|
||||
triggerOnSituation: ''
|
||||
}
|
||||
|
||||
if (processingDailyFiles) {
|
||||
@@ -2589,7 +2617,8 @@
|
||||
status: 0,
|
||||
number: 0,
|
||||
beginRate: 0,
|
||||
endRate: 0
|
||||
endRate: 0,
|
||||
triggerOnSituation: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2605,7 +2634,7 @@
|
||||
currentTrade.endRate = candle.close
|
||||
|
||||
/* Here we will calculate the ongoing ROI */
|
||||
if (bot.VALUES_TO_USE.baseAsset === bot.market.baseAsset) {
|
||||
if (baseAsset === bot.market.baseAsset) {
|
||||
currentTrade.lastTradeROI = (tradePositionRate - candle.close) / tradePositionRate * 100
|
||||
} else {
|
||||
currentTrade.lastTradeROI = (candle.close - tradePositionRate) / tradePositionRate * 100
|
||||
@@ -2626,7 +2655,8 @@
|
||||
lastTradeROI: 0,
|
||||
exitType: 0,
|
||||
beginRate: 0,
|
||||
endRate: 0
|
||||
endRate: 0,
|
||||
takePositionSituation: ''
|
||||
}
|
||||
|
||||
if (processingDailyFiles) {
|
||||
@@ -2638,7 +2668,8 @@
|
||||
lastTradeROI: 0,
|
||||
exitType: 0,
|
||||
beginRate: 0,
|
||||
endRate: 0
|
||||
endRate: 0,
|
||||
takePositionSituation: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2649,7 +2680,7 @@
|
||||
|
||||
function checkAnnouncements(node, value) {
|
||||
/*
|
||||
Value is an optional parameter that represents the value that the announcement is monitoring for change.
|
||||
Value is an optional parameter that represents the value that the announcement is monitoring for change (for numeric values only).
|
||||
If we do receive this value, we will only make the annoucement if the variance is grater than the user pre-defined value
|
||||
for this variance.
|
||||
*/
|
||||
@@ -2673,21 +2704,20 @@
|
||||
|
||||
if (periods > lastPeriodAnnounced) {
|
||||
|
||||
/* The Value Variation is what tells us how much the value already announced must change in order to annouce it again. */
|
||||
let valueVariation
|
||||
try {
|
||||
let code = JSON.parse(announcement.code)
|
||||
valueVariation = code.valueVariation
|
||||
} catch (err) {
|
||||
announcement.error = err.message
|
||||
}
|
||||
if (isNaN(value) === false) {
|
||||
/* The Value Variation is what tells us how much the value already announced must change in order to annouce it again. */
|
||||
let valueVariation
|
||||
|
||||
if (newAnnouncementRecord.value !== undefined && valueVariation !== undefined) {
|
||||
let upperLimit = newAnnouncementRecord.value + newAnnouncementRecord.value * valueVariation / 100
|
||||
let lowerLimit = newAnnouncementRecord.value - newAnnouncementRecord.value * valueVariation / 100
|
||||
if (value > lowerLimit && value < upperLimit) {
|
||||
/* There is not enough variation to announce this again. */
|
||||
return
|
||||
let code = announcement.code
|
||||
valueVariation = code.valueVariation
|
||||
|
||||
if (newAnnouncementRecord.value !== undefined && valueVariation !== undefined) {
|
||||
let upperLimit = newAnnouncementRecord.value + newAnnouncementRecord.value * valueVariation / 100
|
||||
let lowerLimit = newAnnouncementRecord.value - newAnnouncementRecord.value * valueVariation / 100
|
||||
if (value > lowerLimit && value < upperLimit) {
|
||||
/* There is not enough variation to announce this again. */
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2695,6 +2725,7 @@
|
||||
We store the announcement temporarily at an Array to differ its execution, becasue we need to evaulate its formula
|
||||
and at this point in time the potential variables used at the formula are still not set.
|
||||
*/
|
||||
announcement.value = value
|
||||
announcementsToBeMade.push(announcement)
|
||||
|
||||
/* Next, we will remmeber this announcement was already done, so that it is not announced again in further processing of the same day. */
|
||||
@@ -2722,6 +2753,7 @@
|
||||
let formulaValue
|
||||
if (announcement.formula !== undefined) {
|
||||
try {
|
||||
let value = announcement.value
|
||||
formulaValue = eval(announcement.formula.code);
|
||||
} catch (err) {
|
||||
announcement.formula.error = err.message
|
||||
@@ -2729,7 +2761,9 @@
|
||||
}
|
||||
announcement.formulaValue = formulaValue
|
||||
|
||||
bot.SESSION.socialBots.announce(announcement)
|
||||
if (bot.SESSION.socialBots !== undefined) {
|
||||
bot.SESSION.socialBots.announce(announcement)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2741,8 +2775,15 @@
|
||||
|
||||
/* Checking if we should continue processing this loop or not.*/
|
||||
if (bot.STOP_SESSION === true) {
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> controlLoop -> We are going to stop here bacause we were requested to stop processing."); }
|
||||
console.log("[INFO] runSimulation -> controlLoop -> We are going to stop here bacause we were requested to stop processing.")
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> controlLoop -> We are going to stop here bacause we were requested to stop processing this session."); }
|
||||
console.log("[INFO] runSimulation -> controlLoop -> We are going to stop here bacause we were requested to stop processing this session.")
|
||||
afterLoop()
|
||||
return
|
||||
}
|
||||
|
||||
if (global.STOP_TASK_GRACEFULLY === true) {
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] runSimulation -> controlLoop -> We are going to stop here bacause we were requested to stop processing this task."); }
|
||||
console.log("[INFO] runSimulation -> controlLoop -> We are going to stop here bacause we were requested to stop processing this task.")
|
||||
afterLoop()
|
||||
return
|
||||
}
|
||||
@@ -2791,7 +2832,8 @@
|
||||
status: yesterday.currentStrategy.status,
|
||||
number: yesterday.currentStrategy.number,
|
||||
beginRate: yesterday.currentStrategy.beginRate,
|
||||
endRate: yesterday.currentStrategy.endRate
|
||||
endRate: yesterday.currentStrategy.endRate,
|
||||
triggerOnSituation: yesterday.currentStrategy.triggerOnSituation
|
||||
}
|
||||
|
||||
interExecutionMemory.currentTrade = {
|
||||
@@ -2801,7 +2843,8 @@
|
||||
profit: yesterday.currentTrade.profit,
|
||||
exitType: yesterday.currentTrade.exitType,
|
||||
beginRate: yesterday.currentTrade.beginRate,
|
||||
endRate: yesterday.currentTrade.endRate
|
||||
endRate: yesterday.currentTrade.endRate,
|
||||
takePositionSituation: yesterday.currentTrade.takePositionSituation
|
||||
}
|
||||
|
||||
interExecutionMemory.balanceBaseAsset = yesterday.balanceBaseAsset;
|
||||
|
||||
Reference in new issue
Block a user