Merge pull request #146 from AAMasters/develop

Beta Release Candidate
This commit is contained in:
Luis Fernando Molina authored and GitHub committed 2020-04-03 18:14:30 +02:00
commit b725e85e0e
5 files changed
+427 -476

No files matched your search

+203 -182
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;