Async Await implementation at Trading Process
This commit is contained in:
1 parent
ea047363af
commit
fdbffef52e
17 files changed
+902
-905
No files matched your search
@@ -4,7 +4,7 @@ const path = require('path')
|
||||
exports.newFileStorage = function newFileStorage(logger, host, port) {
|
||||
|
||||
const MODULE_NAME = 'FileStorage'
|
||||
const MAX_RETRY = 30
|
||||
const MAX_RETRY = 10
|
||||
const FAST_RETRY_TIME_IN_MILISECONDS = 500
|
||||
const SLOW_RETRY_TIME_IN_MILISECONDS = 2000
|
||||
|
||||
@@ -17,6 +17,8 @@ exports.newFileStorage = function newFileStorage(logger, host, port) {
|
||||
}
|
||||
|
||||
let thisObject = {
|
||||
asyncGetTextFile: asyncGetTextFile,
|
||||
asyncCreateTextFile: asyncCreateTextFile,
|
||||
getTextFile: getTextFile,
|
||||
createTextFile: createTextFile,
|
||||
deleteTextFile: deleteTextFile
|
||||
@@ -24,6 +26,41 @@ exports.newFileStorage = function newFileStorage(logger, host, port) {
|
||||
|
||||
return thisObject
|
||||
|
||||
async function asyncGetTextFile(filePath, noRetry, canUsePrevious) {
|
||||
/* This function allows its caller to work with async / await instead of callbacks */
|
||||
let promise = new Promise((resolve, reject) => {
|
||||
|
||||
getTextFile(filePath, onFileRead, noRetry, canUsePrevious)
|
||||
function onFileRead(err, text) {
|
||||
|
||||
let response = {
|
||||
err: err,
|
||||
text: text
|
||||
}
|
||||
resolve(response)
|
||||
}
|
||||
})
|
||||
|
||||
return promise
|
||||
}
|
||||
|
||||
async function asyncCreateTextFile(filePath, fileContent, keepPrevious, noTemp) {
|
||||
/* This function allows its caller to work with async / await instead of callbacks */
|
||||
let promise = new Promise((resolve, reject) => {
|
||||
|
||||
createTextFile(filePath, fileContent, onFileWriten, keepPrevious, noTemp)
|
||||
function onFileWriten(err) {
|
||||
|
||||
let response = {
|
||||
err: err
|
||||
}
|
||||
resolve(response)
|
||||
}
|
||||
})
|
||||
|
||||
return promise
|
||||
}
|
||||
|
||||
function getTextFile(filePath, callBackFunction, noRetry, canUsePrevious) {
|
||||
|
||||
let currentRetryGetTextFile = 0
|
||||
@@ -160,7 +197,7 @@ exports.newFileStorage = function newFileStorage(logger, host, port) {
|
||||
}
|
||||
|
||||
function retry() {
|
||||
console.log(new Date(), ' Retry #: ' + currentRetryGetTextFile, fileLocation)
|
||||
console.log(new Date(), 'Read File 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)
|
||||
@@ -216,12 +253,12 @@ exports.newFileStorage = function newFileStorage(logger, host, port) {
|
||||
*/
|
||||
const fs = require('fs')
|
||||
if (noTemp === true) {
|
||||
fs.writeFile(fileLocation, fileContent, onFileWritenn)
|
||||
fs.writeFile(fileLocation, fileContent, onFileWriten)
|
||||
} else {
|
||||
fs.writeFile(fileLocation + '.tmp', fileContent, onFileWritenn)
|
||||
fs.writeFile(fileLocation + '.tmp', fileContent, onFileWriten)
|
||||
}
|
||||
|
||||
function onFileWritenn(err) {
|
||||
function onFileWriten(err) {
|
||||
let retryTimeToUse = FAST_RETRY_TIME_IN_MILISECONDS
|
||||
if (currentRetryWriteTextFile > MAX_RETRY - 2) {
|
||||
retryTimeToUse = SLOW_RETRY_TIME_IN_MILISECONDS
|
||||
|
||||
@@ -9,7 +9,6 @@ exports.newTradingEpisode = function newTradingEpisode(bot, logger, tradingEngin
|
||||
openEpisode: openEpisode,
|
||||
updateExitType: updateExitType,
|
||||
closeEpisode: closeEpisode,
|
||||
calculateResults: calculateResults,
|
||||
calculateStatistics: calculateStatistics,
|
||||
initialize: initialize,
|
||||
finalize: finalize
|
||||
@@ -116,116 +115,160 @@ exports.newTradingEpisode = function newTradingEpisode(bot, logger, tradingEngin
|
||||
|
||||
function calculateStatistics() {
|
||||
|
||||
/* Updating Profit Loss */
|
||||
tradingEngine.current.episode.episodeStatistics.profitLoss.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value * tradingEngine.current.episode.candle.close.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value
|
||||
|
||||
tradingEngine.current.episode.episodeStatistics.profitLoss.value = global.PRECISE(tradingEngine.current.episode.episodeStatistics.profitLoss.value, 10)
|
||||
|
||||
/* Updating ROI */
|
||||
tradingEngine.current.episode.episodeStatistics.ROI.value =
|
||||
(
|
||||
sessionParameters.sessionBaseAsset.config.initialBalance * tradingEngine.current.episode.candle.close.value +
|
||||
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value * tradingEngine.current.episode.candle.close.value +
|
||||
sessionParameters.sessionQuotedAsset.config.initialBalance +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value
|
||||
) / (
|
||||
sessionParameters.sessionBaseAsset.config.initialBalance * tradingEngine.current.episode.candle.close.value +
|
||||
calculateAssetsStatistics()
|
||||
calculateEpisodeStatistics()
|
||||
|
||||
function calculateAssetsStatistics() {
|
||||
|
||||
/* Updating Hits & Fails */
|
||||
if (tradingEngine.current.position.positionBaseAsset.profitLoss.value > 0) {
|
||||
tradingEngine.current.episode.episodeBaseAsset.hits.value++
|
||||
} else {
|
||||
tradingEngine.current.episode.episodeBaseAsset.fails.value++
|
||||
}
|
||||
if (tradingEngine.current.position.positionQuotedAsset.profitLoss.value > 0) {
|
||||
tradingEngine.current.episode.episodeQuotedAsset.hits.value++
|
||||
} else {
|
||||
tradingEngine.current.episode.episodeQuotedAsset.fails.value++
|
||||
}
|
||||
|
||||
/* Updating Profit Loss */
|
||||
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.balance.value -
|
||||
sessionParameters.sessionBaseAsset.config.initialBalance
|
||||
|
||||
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value =
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value -
|
||||
sessionParameters.sessionQuotedAsset.config.initialBalance
|
||||
) - 1
|
||||
|
||||
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value = global.PRECISE(tradingEngine.current.episode.episodeBaseAsset.profitLoss.value, 10)
|
||||
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value = global.PRECISE(tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value, 10)
|
||||
|
||||
/*
|
||||
Updating ROI
|
||||
|
||||
https://www.investopedia.com/articles/basics/10/guide-to-calculating-roi.asp
|
||||
*/
|
||||
tradingEngine.current.episode.episodeBaseAsset.ROI.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value /
|
||||
tradingEngine.current.episode.episodeBaseAsset.beginBalance.value * 100
|
||||
|
||||
tradingEngine.current.episode.episodeQuotedAsset.ROI.value =
|
||||
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value /
|
||||
tradingEngine.current.episode.episodeQuotedAsset.beginBalance.value * 100
|
||||
|
||||
tradingEngine.current.episode.episodeBaseAsset.ROI.value = global.PRECISE(tradingEngine.current.episode.episodeBaseAsset.ROI.value, 10)
|
||||
tradingEngine.current.episode.episodeQuotedAsset.ROI.value = global.PRECISE(tradingEngine.current.episode.episodeQuotedAsset.ROI.value, 10)
|
||||
|
||||
/* Updating Hit Ratio */
|
||||
tradingEngine.current.episode.episodeBaseAsset.hitRatio.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.hits.value /
|
||||
tradingEngine.current.episode.episodeCounters.positions.value
|
||||
|
||||
tradingEngine.current.episode.episodeQuotedAsset.hitRatio.value =
|
||||
tradingEngine.current.episode.episodeQuotedAsset.hits.value /
|
||||
tradingEngine.current.episode.episodeCounters.positions.value
|
||||
|
||||
tradingEngine.current.episode.episodeBaseAsset.hitRatio.value = global.PRECISE(tradingEngine.current.episode.episodeBaseAsset.hitRatio.value, 10)
|
||||
tradingEngine.current.episode.episodeQuotedAsset.hitRatio.value = global.PRECISE(tradingEngine.current.episode.episodeQuotedAsset.hitRatio.value, 10)
|
||||
|
||||
/*
|
||||
Updating Annualized Rate Of Return
|
||||
|
||||
https://www.investopedia.com/terms/a/annualized-rate.asp
|
||||
*/
|
||||
tradingEngine.current.episode.episodeBaseAsset.annualizedRateOfReturn.value =
|
||||
Math.pow(
|
||||
(
|
||||
tradingEngine.current.episode.episodeBaseAsset.beginBalance.value +
|
||||
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value
|
||||
) / tradingEngine.current.episode.episodeBaseAsset.beginBalance.value
|
||||
,
|
||||
(365 / tradingEngine.current.episode.episodeStatistics.days.value)
|
||||
) - 1
|
||||
|
||||
tradingEngine.current.episode.episodeQuotedAsset.annualizedRateOfReturn.value =
|
||||
Math.pow(
|
||||
(
|
||||
tradingEngine.current.episode.episodeQuotedAsset.beginBalance.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value
|
||||
) / tradingEngine.current.episode.episodeQuotedAsset.beginBalance.value
|
||||
,
|
||||
(365 / tradingEngine.current.episode.episodeStatistics.days.value)
|
||||
) - 1
|
||||
|
||||
tradingEngine.current.episode.episodeBaseAsset.annualizedRateOfReturn.value = global.PRECISE(tradingEngine.current.episode.episodeBaseAsset.annualizedRateOfReturn.value, 10)
|
||||
tradingEngine.current.episode.episodeQuotedAsset.annualizedRateOfReturn.value = global.PRECISE(tradingEngine.current.episode.episodeQuotedAsset.annualizedRateOfReturn.value, 10)
|
||||
|
||||
/* Updating Hit or Fail */
|
||||
if (tradingEngine.current.episode.episodeBaseAsset.profitLoss.value > 0) {
|
||||
tradingEngine.current.episode.episodeBaseAsset.hitFail.value = 'Hit'
|
||||
} else {
|
||||
tradingEngine.current.episode.episodeBaseAsset.hitFail.value = 'Fail'
|
||||
}
|
||||
if (tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value > 0) {
|
||||
tradingEngine.current.episode.episodeQuotedAsset.hitFail.value = 'Hit'
|
||||
} else {
|
||||
tradingEngine.current.episode.episodeQuotedAsset.hitFail.value = 'Fail'
|
||||
}
|
||||
}
|
||||
|
||||
tradingEngine.current.episode.episodeStatistics.ROI.value = global.PRECISE(tradingEngine.current.episode.episodeStatistics.ROI.value, 10)
|
||||
|
||||
/* Updating Annualized Rate Of Return */
|
||||
tradingEngine.current.episode.episodeStatistics.annualizedRateOfReturn.value =
|
||||
tradingEngine.current.episode.episodeStatistics.ROI.value /
|
||||
tradingEngine.current.episode.episodeStatistics.days.value * 365
|
||||
|
||||
tradingEngine.current.episode.episodeStatistics.annualizedRateOfReturn.value = global.PRECISE(tradingEngine.current.episode.episodeStatistics.annualizedRateOfReturn.value, 10)
|
||||
|
||||
/* Updating Hit or Fail */
|
||||
if (tradingEngine.current.episode.episodeStatistics.profitLoss.value > 0) {
|
||||
tradingEngine.current.episode.episodeStatistics.hitFail.value = 'Hit'
|
||||
} else {
|
||||
tradingEngine.current.episode.episodeStatistics.hitFail.value = 'Fail'
|
||||
function calculateEpisodeStatistics() {
|
||||
/* Updating Profit Loss */
|
||||
tradingEngine.current.episode.episodeStatistics.profitLoss.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value * tradingEngine.current.episode.candle.close.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value
|
||||
|
||||
tradingEngine.current.episode.episodeStatistics.profitLoss.value = global.PRECISE(tradingEngine.current.episode.episodeStatistics.profitLoss.value, 10)
|
||||
|
||||
/*
|
||||
Updating ROI
|
||||
|
||||
https://www.investopedia.com/articles/basics/10/guide-to-calculating-roi.asp
|
||||
*/
|
||||
tradingEngine.current.episode.episodeStatistics.ROI.value =
|
||||
(
|
||||
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value * tradingEngine.current.episode.endRate.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value
|
||||
) / (
|
||||
tradingEngine.current.episode.episodeBaseAsset.beginBalance.value * tradingEngine.current.episode.beginRate.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.beginBalance.value
|
||||
) * 100
|
||||
|
||||
tradingEngine.current.episode.episodeStatistics.ROI.value = global.PRECISE(tradingEngine.current.episode.episodeStatistics.ROI.value, 10)
|
||||
|
||||
/*
|
||||
Updating Annualized Rate Of Return
|
||||
|
||||
https://www.investopedia.com/terms/a/annualized-rate.asp
|
||||
*/
|
||||
tradingEngine.current.episode.episodeStatistics.annualizedRateOfReturn.value =
|
||||
Math.pow(
|
||||
(
|
||||
tradingEngine.current.episode.episodeBaseAsset.beginBalance.value * tradingEngine.current.episode.beginRate.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.beginBalance.value +
|
||||
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value
|
||||
) /
|
||||
(
|
||||
tradingEngine.current.episode.episodeBaseAsset.beginBalance.value * tradingEngine.current.episode.beginRate.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.beginBalance.value
|
||||
)
|
||||
,
|
||||
(365 / tradingEngine.current.episode.episodeStatistics.days.value)
|
||||
) - 1
|
||||
|
||||
tradingEngine.current.episode.episodeStatistics.annualizedRateOfReturn.value = global.PRECISE(tradingEngine.current.episode.episodeStatistics.annualizedRateOfReturn.value, 10)
|
||||
|
||||
/* Updating Hit or Fail */
|
||||
if (tradingEngine.current.episode.episodeStatistics.profitLoss.value > 0) {
|
||||
tradingEngine.current.episode.episodeStatistics.hitFail.value = 'Hit'
|
||||
} else {
|
||||
tradingEngine.current.episode.episodeStatistics.hitFail.value = 'Fail'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function calculateResults() {
|
||||
|
||||
/* Updating Hits & Fails */
|
||||
if (tradingEngine.current.position.positionBaseAsset.profitLoss.value > 0) {
|
||||
tradingEngine.current.episode.episodeBaseAsset.hits.value++
|
||||
} else {
|
||||
tradingEngine.current.episode.episodeBaseAsset.fails.value++
|
||||
}
|
||||
if (tradingEngine.current.position.positionQuotedAsset.profitLoss.value > 0) {
|
||||
tradingEngine.current.episode.episodeQuotedAsset.hits.value++
|
||||
} else {
|
||||
tradingEngine.current.episode.episodeQuotedAsset.fails.value++
|
||||
}
|
||||
|
||||
/* Updating Profit Loss */
|
||||
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.balance.value -
|
||||
sessionParameters.sessionBaseAsset.config.initialBalance
|
||||
|
||||
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value =
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value -
|
||||
sessionParameters.sessionQuotedAsset.config.initialBalance
|
||||
|
||||
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value = global.PRECISE(tradingEngine.current.episode.episodeBaseAsset.profitLoss.value, 10)
|
||||
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value = global.PRECISE(tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value, 10)
|
||||
|
||||
/* Updating ROI */
|
||||
tradingEngine.current.episode.episodeBaseAsset.ROI.value =
|
||||
(sessionParameters.sessionBaseAsset.config.initialBalance + tradingEngine.current.episode.episodeBaseAsset.profitLoss.value) /
|
||||
sessionParameters.sessionBaseAsset.config.initialBalance - 1
|
||||
|
||||
tradingEngine.current.episode.episodeQuotedAsset.ROI.value =
|
||||
(sessionParameters.sessionQuotedAsset.config.initialBalance + tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value) /
|
||||
sessionParameters.sessionQuotedAsset.config.initialBalance - 1
|
||||
|
||||
tradingEngine.current.episode.episodeBaseAsset.ROI.value = global.PRECISE(tradingEngine.current.episode.episodeBaseAsset.ROI.value, 10)
|
||||
tradingEngine.current.episode.episodeQuotedAsset.ROI.value = global.PRECISE(tradingEngine.current.episode.episodeQuotedAsset.ROI.value, 10)
|
||||
|
||||
/* Updating Hit Ratio */
|
||||
tradingEngine.current.episode.episodeBaseAsset.hitRatio.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.hits.value /
|
||||
tradingEngine.current.episode.episodeCounters.positions.value
|
||||
|
||||
tradingEngine.current.episode.episodeQuotedAsset.hitRatio.value =
|
||||
tradingEngine.current.episode.episodeQuotedAsset.hits.value /
|
||||
tradingEngine.current.episode.episodeCounters.positions.value
|
||||
|
||||
tradingEngine.current.episode.episodeBaseAsset.hitRatio.value = global.PRECISE(tradingEngine.current.episode.episodeBaseAsset.hitRatio.value, 10)
|
||||
tradingEngine.current.episode.episodeQuotedAsset.hitRatio.value = global.PRECISE(tradingEngine.current.episode.episodeQuotedAsset.hitRatio.value, 10)
|
||||
|
||||
/* Updating Annualized Rate Of Return */
|
||||
tradingEngine.current.episode.episodeBaseAsset.annualizedRateOfReturn.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.ROI.value /
|
||||
tradingEngine.current.episode.episodeStatistics.days.value * 365
|
||||
|
||||
tradingEngine.current.episode.episodeQuotedAsset.annualizedRateOfReturn.value =
|
||||
tradingEngine.current.episode.episodeQuotedAsset.ROI.value /
|
||||
tradingEngine.current.episode.episodeStatistics.days.value * 365
|
||||
|
||||
tradingEngine.current.episode.episodeBaseAsset.annualizedRateOfReturn.value = global.PRECISE(tradingEngine.current.episode.episodeBaseAsset.annualizedRateOfReturn.value, 10)
|
||||
tradingEngine.current.episode.episodeQuotedAsset.annualizedRateOfReturn.value = global.PRECISE(tradingEngine.current.episode.episodeQuotedAsset.annualizedRateOfReturn.value, 10)
|
||||
|
||||
/* Updating Hit or Fail */
|
||||
if (tradingEngine.current.episode.episodeBaseAsset.profitLoss.value > 0) {
|
||||
tradingEngine.current.episode.episodeBaseAsset.hitFail.value = 'Hit'
|
||||
} else {
|
||||
tradingEngine.current.episode.episodeBaseAsset.hitFail.value = 'Fail'
|
||||
}
|
||||
if (tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value > 0) {
|
||||
tradingEngine.current.episode.episodeQuotedAsset.hitFail.value = 'Hit'
|
||||
} else {
|
||||
tradingEngine.current.episode.episodeQuotedAsset.hitFail.value = 'Fail'
|
||||
}
|
||||
}
|
||||
|
||||
function updateDistanceToEventsCounters() {
|
||||
/* Keeping Distance Counters Up-to-date while avoinding counting before the first event happens. */
|
||||
|
||||
@@ -3,7 +3,6 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, UTILITIES, FIL
|
||||
This module will load if necesary all the data outputs so that they can be appended with new
|
||||
records if needed. After running the simulation, it will save all the data outputs.
|
||||
*/
|
||||
const FULL_LOG = true
|
||||
const MODULE_NAME = 'Trading Bot'
|
||||
|
||||
let thisObject = {
|
||||
@@ -24,21 +23,13 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, UTILITIES, FIL
|
||||
commons = undefined
|
||||
}
|
||||
|
||||
function initialize(callBackFunction) {
|
||||
try {
|
||||
logger.fileName = MODULE_NAME
|
||||
logger.initialize()
|
||||
function initialize() {
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE)
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, '[ERROR] initialize -> err = ' + err.stack)
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
|
||||
function start(chart, timeFrame, timeFrameLabel, currentDay, callBackFunction) {
|
||||
async function start(chart, timeFrame, timeFrameLabel, currentDay) {
|
||||
try {
|
||||
bot.processingDailyFiles
|
||||
|
||||
if (timeFrame > global.dailyFilePeriods[0][0]) {
|
||||
bot.processingDailyFiles = false
|
||||
} else {
|
||||
@@ -51,10 +42,6 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, UTILITIES, FIL
|
||||
|
||||
let outputDatasets = bot.processNode.referenceParent.processOutput.outputDatasets
|
||||
let market = bot.market
|
||||
let totalFilesToBeRead = 0
|
||||
let totalFilesRead = 0
|
||||
let totalFilesToBeWritten = 0
|
||||
let totalFilesWritten = 0
|
||||
let outputDatasetsMap = new Map()
|
||||
|
||||
if (bot.FIRST_EXECUTION === true && bot.RESUME === false) {
|
||||
@@ -63,21 +50,27 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, UTILITIES, FIL
|
||||
*/
|
||||
bot.simulationState.tradingEngine = bot.TRADING_ENGINE
|
||||
bot.simulationState.tradingSystem = bot.TRADING_SYSTEM
|
||||
initializeOutputs()
|
||||
await initializeOutputs()
|
||||
} else {
|
||||
readFiles()
|
||||
await readFiles()
|
||||
}
|
||||
|
||||
await tradingSimulation.runSimulation(
|
||||
chart,
|
||||
outputDatasetsMap,
|
||||
writeFiles
|
||||
)
|
||||
return
|
||||
|
||||
function initializeOutputs() {
|
||||
async function initializeOutputs() {
|
||||
if (bot.processingDailyFiles) {
|
||||
initializeDailyFiles()
|
||||
await initializeDailyFiles()
|
||||
} else {
|
||||
initializeMarketFiles()
|
||||
await initializeMarketFiles()
|
||||
}
|
||||
}
|
||||
|
||||
function initializeDailyFiles() {
|
||||
async function initializeDailyFiles() {
|
||||
for (let i = 0; i < outputDatasets.length; i++) {
|
||||
let outputDatasetNode = outputDatasets[i]
|
||||
let dataset = outputDatasetNode.referenceParent
|
||||
@@ -86,10 +79,9 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, UTILITIES, FIL
|
||||
outputDatasetsMap.set(dataset.parentNode.config.codeName, [])
|
||||
}
|
||||
}
|
||||
runSimulation()
|
||||
}
|
||||
|
||||
function initializeMarketFiles() {
|
||||
async function initializeMarketFiles() {
|
||||
for (let i = 0; i < outputDatasets.length; i++) {
|
||||
let outputDatasetNode = outputDatasets[i]
|
||||
let dataset = outputDatasetNode.referenceParent
|
||||
@@ -98,23 +90,22 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, UTILITIES, FIL
|
||||
outputDatasetsMap.set(dataset.parentNode.config.codeName, [])
|
||||
}
|
||||
}
|
||||
runSimulation()
|
||||
}
|
||||
|
||||
function readFiles() {
|
||||
async function readFiles() {
|
||||
/*
|
||||
This bot have an output of files that it generates. At every call to the bot, it needs to read the previously generated
|
||||
files in order to later append more information after the execution is over. Here in this function we are going to
|
||||
read those output files and get them ready for appending content during the simulation.
|
||||
*/
|
||||
if (bot.processingDailyFiles) {
|
||||
readDailyFiles()
|
||||
await readDailyFiles()
|
||||
} else {
|
||||
readMarketFiles()
|
||||
await readMarketFiles()
|
||||
}
|
||||
}
|
||||
|
||||
function readMarketFiles() {
|
||||
async function readMarketFiles() {
|
||||
for (let i = 0; i < outputDatasets.length; i++) {
|
||||
let outputDatasetNode = outputDatasets[i]
|
||||
let dataset = outputDatasetNode.referenceParent
|
||||
@@ -124,12 +115,12 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, UTILITIES, FIL
|
||||
let fileName = 'Data.json'
|
||||
let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel
|
||||
|
||||
readOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
|
||||
await readOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function readDailyFiles() {
|
||||
async function readDailyFiles() {
|
||||
for (let i = 0; i < outputDatasets.length; i++) {
|
||||
let outputDatasetNode = outputDatasets[i]
|
||||
let dataset = outputDatasetNode.referenceParent
|
||||
@@ -140,70 +131,38 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, UTILITIES, FIL
|
||||
let fileName = 'Data.json'
|
||||
let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel + "/" + dateForPath
|
||||
|
||||
readOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
|
||||
await readOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function readOutputFile(fileName, filePath, productName) {
|
||||
totalFilesToBeRead++
|
||||
async function readOutputFile(fileName, filePath, productName) {
|
||||
filePath += '/' + fileName
|
||||
fileStorage.getTextFile(filePath, onFileRead, true)
|
||||
|
||||
function onFileRead(err, text) {
|
||||
try {
|
||||
let response = await fileStorage.asyncGetTextFile(filePath, true)
|
||||
|
||||
if (err.message === 'File does not exist.') {
|
||||
outputDatasetsMap.set(productName, [])
|
||||
anotherFileRead()
|
||||
return
|
||||
}
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readOutputFile -> onFileRead -> err = ' + err.stack)
|
||||
logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readOutputFile -> onFileRead -> filePath = ' + filePath)
|
||||
logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readOutputFile -> onFileRead -> market = ' + market.baseAsset + '_' + market.quotedAsset)
|
||||
|
||||
callBackFunction(err)
|
||||
return
|
||||
}
|
||||
|
||||
outputDatasetsMap.set(productName, JSON.parse(text))
|
||||
anotherFileRead()
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readOutputFile -> onFileRead -> err = ' + err.stack)
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
if (response.err.message === 'File does not exist.') {
|
||||
outputDatasetsMap.set(productName, [])
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
function anotherFileRead() {
|
||||
totalFilesRead++
|
||||
if (totalFilesRead === totalFilesToBeRead) {
|
||||
runSimulation()
|
||||
if (response.err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
throw(response.err)
|
||||
}
|
||||
outputDatasetsMap.set(productName, JSON.parse(text))
|
||||
}
|
||||
|
||||
function runSimulation() {
|
||||
tradingSimulation.runSimulation(
|
||||
chart,
|
||||
outputDatasetsMap,
|
||||
writeFiles,
|
||||
callBackFunction)
|
||||
}
|
||||
|
||||
function writeFiles() {
|
||||
async function writeFiles() {
|
||||
/*
|
||||
The output of files which were appended with information during the simulation execution, now needs to be saved.
|
||||
*/
|
||||
if (bot.processingDailyFiles) {
|
||||
writeDailyFiles()
|
||||
await writeDailyFiles()
|
||||
} else {
|
||||
writeMarketFiles()
|
||||
await writeMarketFiles()
|
||||
}
|
||||
}
|
||||
|
||||
function writeMarketFiles() {
|
||||
async function writeMarketFiles() {
|
||||
for (let i = 0; i < outputDatasets.length; i++) {
|
||||
let outputDatasetNode = outputDatasets[i]
|
||||
let dataset = outputDatasetNode.referenceParent
|
||||
@@ -213,12 +172,12 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, UTILITIES, FIL
|
||||
let fileName = 'Data.json'
|
||||
let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel
|
||||
|
||||
writeOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
|
||||
await writeOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeDailyFiles() {
|
||||
async function writeDailyFiles() {
|
||||
for (let i = 0; i < outputDatasets.length; i++) {
|
||||
let outputDatasetNode = outputDatasets[i]
|
||||
let dataset = outputDatasetNode.referenceParent
|
||||
@@ -229,47 +188,25 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, UTILITIES, FIL
|
||||
let fileName = 'Data.json'
|
||||
let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel + "/" + dateForPath
|
||||
|
||||
writeOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
|
||||
await writeOutputFile(fileName, filePath, dataset.parentNode.config.codeName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function writeOutputFile(fileName, filePath, productName) {
|
||||
totalFilesToBeWritten++
|
||||
async function writeOutputFile(fileName, filePath, productName) {
|
||||
filePath += '/' + fileName
|
||||
let fileContent = JSON.stringify(outputDatasetsMap.get(productName))
|
||||
|
||||
fileStorage.createTextFile(filePath, fileContent, onFileCreated)
|
||||
let response = await fileStorage.asyncCreateTextFile(filePath, fileContent)
|
||||
|
||||
function onFileCreated(err) {
|
||||
try {
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readOutputFile -> onFileRead -> err = ' + err.stack)
|
||||
logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readOutputFile -> onFileRead -> filePath = ' + filePath)
|
||||
logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readOutputFile -> onFileRead -> market = ' + market.baseAsset + '_' + market.quotedAsset)
|
||||
|
||||
callBackFunction(err)
|
||||
return
|
||||
}
|
||||
|
||||
anotherFileWritten()
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, '[ERROR] start -> readMarketFiles -> readOutputFile -> onFileRead -> err = ' + err.stack)
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function anotherFileWritten() {
|
||||
totalFilesWritten++
|
||||
if (totalFilesWritten === totalFilesToBeWritten) {
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE)
|
||||
if (response.err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
throw(response.err)
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, '[ERROR] start -> err = ' + err.stack)
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
|
||||
throw(global.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
|
||||
let thisObject = {
|
||||
mantain: mantain,
|
||||
reset: reset,
|
||||
calculateStatistics: calculateStatistics,
|
||||
openPosition: openPosition,
|
||||
closingPosition: closingPosition,
|
||||
closePosition: closePosition,
|
||||
@@ -87,9 +88,6 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
|
||||
tradingEngine.current.position.positionBaseAsset.endBalance.value = tradingEngine.current.episode.episodeBaseAsset.balance.value
|
||||
tradingEngine.current.position.positionQuotedAsset.endBalance.value = tradingEngine.current.episode.episodeQuotedAsset.balance.value
|
||||
|
||||
/* Position Statistics & Results */
|
||||
updateStatistics()
|
||||
updateResults()
|
||||
/*
|
||||
Now that the position is closed, it is the right time to move this position from current to last at the Trading Engine data structure.
|
||||
*/
|
||||
@@ -258,82 +256,84 @@ exports.newTradingPosition = function newTradingPosition(bot, logger, tradingEng
|
||||
}
|
||||
}
|
||||
|
||||
function updateStatistics() {
|
||||
function calculateStatistics(tradingEngineStageNode) {
|
||||
|
||||
/* Profit Loss Calculation */
|
||||
tradingEngine.current.position.positionStatistics.profitLoss.value =
|
||||
(
|
||||
tradingEngine.current.episode.episodeBaseAsset.balance.value * tradingEngine.current.position.endRate.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value
|
||||
) -
|
||||
(
|
||||
tradingEngine.current.position.positionBaseAsset.beginBalance * tradingEngine.current.position.beginRate.value +
|
||||
calculateAssetsStatistics()
|
||||
calculatePositionStatistics()
|
||||
|
||||
function calculateAssetsStatistics() {
|
||||
/* Profit Loss Calculation */
|
||||
tradingEngine.current.position.positionBaseAsset.profitLoss.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.balance.value -
|
||||
tradingEngine.current.position.positionBaseAsset.beginBalance
|
||||
|
||||
tradingEngine.current.position.positionQuotedAsset.profitLoss.value =
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value -
|
||||
tradingEngine.current.position.positionQuotedAsset.beginBalance
|
||||
)
|
||||
tradingEngine.current.position.positionStatistics.profitLoss.value = global.PRECISE(tradingEngine.current.position.positionStatistics.profitLoss.value, 10)
|
||||
|
||||
/* ROI Calculation */
|
||||
tradingEngine.current.position.positionStatistics.ROI.value =
|
||||
(
|
||||
tradingEngine.current.position.positionStatistics.profitLoss.value
|
||||
)
|
||||
* 100 /
|
||||
(
|
||||
tradingEngine.current.position.positionBaseAsset.beginBalance * tradingEngine.current.position.beginRate.value +
|
||||
tradingEngine.current.position.positionQuotedAsset.beginBalance
|
||||
)
|
||||
tradingEngine.current.position.positionStatistics.ROI.value = global.PRECISE(tradingEngine.current.position.positionStatistics.ROI.value, 10)
|
||||
|
||||
/* Hit Fail Calculation */
|
||||
if (tradingEngine.current.position.positionStatistics.ROI.value > 0) {
|
||||
tradingEngine.current.position.positionStatistics.hitFail.value = 'Hit'
|
||||
} else {
|
||||
tradingEngine.current.position.positionStatistics.hitFail.value = 'Fail'
|
||||
|
||||
tradingEngine.current.position.positionBaseAsset.profitLoss.value = global.PRECISE(tradingEngine.current.position.positionBaseAsset.profitLoss.value, 10)
|
||||
tradingEngine.current.position.positionQuotedAsset.profitLoss.value = global.PRECISE(tradingEngine.current.position.positionQuotedAsset.profitLoss.value, 10)
|
||||
|
||||
/* ROI Calculation */
|
||||
tradingEngine.current.position.positionBaseAsset.ROI.value =
|
||||
tradingEngine.current.position.positionBaseAsset.profitLoss.value * 100 /
|
||||
tradingEngine.current.strategyOpenStage.stageBaseAsset.sizeFilled.value
|
||||
|
||||
tradingEngine.current.position.positionQuotedAsset.ROI.value =
|
||||
tradingEngine.current.position.positionQuotedAsset.profitLoss.value * 100 /
|
||||
tradingEngine.current.strategyOpenStage.stageQuotedAsset.sizeFilled.value
|
||||
|
||||
tradingEngine.current.position.positionBaseAsset.ROI.value = global.PRECISE(tradingEngine.current.position.positionBaseAsset.ROI.value, 10)
|
||||
tradingEngine.current.position.positionQuotedAsset.ROI.value = global.PRECISE(tradingEngine.current.position.positionQuotedAsset.ROI.value, 10)
|
||||
|
||||
/* Hit Fail Calculation */
|
||||
if (tradingEngine.current.position.positionBaseAsset.ROI.value > 0) {
|
||||
tradingEngine.current.position.positionBaseAsset.hitFail.value = 'Hit'
|
||||
} else {
|
||||
tradingEngine.current.position.positionBaseAsset.hitFail.value = 'Fail'
|
||||
}
|
||||
if (tradingEngine.current.position.positionQuotedAsset.ROI.value > 0) {
|
||||
tradingEngine.current.position.positionQuotedAsset.hitFail.value = 'Hit'
|
||||
} else {
|
||||
tradingEngine.current.position.positionQuotedAsset.hitFail.value = 'Fail'
|
||||
}
|
||||
}
|
||||
|
||||
/* Days Calculation */
|
||||
tradingEngine.current.position.positionStatistics.days.value =
|
||||
tradingEngine.current.position.positionCounters.periods.value *
|
||||
sessionParameters.timeFrame.config.value / global.ONE_DAY_IN_MILISECONDS
|
||||
function calculatePositionStatistics() {
|
||||
/* Profit Loss Calculation */
|
||||
tradingEngine.current.position.positionStatistics.profitLoss.value =
|
||||
(
|
||||
tradingEngine.current.episode.episodeBaseAsset.profitLoss.value * tradingEngine.current.position.endRate.value +
|
||||
tradingEngine.current.episode.episodeQuotedAsset.profitLoss.value
|
||||
)
|
||||
|
||||
tradingEngine.current.position.positionStatistics.days.value = global.PRECISE(tradingEngine.current.position.positionStatistics.days.value, 10)
|
||||
}
|
||||
|
||||
function updateResults() {
|
||||
/* Profit Loss Calculation */
|
||||
tradingEngine.current.position.positionBaseAsset.profitLoss.value =
|
||||
tradingEngine.current.episode.episodeBaseAsset.balance.value -
|
||||
tradingEngine.current.position.positionBaseAsset.beginBalance
|
||||
|
||||
tradingEngine.current.position.positionQuotedAsset.profitLoss.value =
|
||||
tradingEngine.current.episode.episodeQuotedAsset.balance.value -
|
||||
tradingEngine.current.position.positionQuotedAsset.beginBalance
|
||||
|
||||
tradingEngine.current.position.positionBaseAsset.profitLoss.value = global.PRECISE(tradingEngine.current.position.positionBaseAsset.profitLoss.value, 10)
|
||||
tradingEngine.current.position.positionQuotedAsset.profitLoss.value = global.PRECISE(tradingEngine.current.position.positionQuotedAsset.profitLoss.value, 10)
|
||||
|
||||
/* ROI Calculation */
|
||||
tradingEngine.current.position.positionBaseAsset.ROI.value =
|
||||
tradingEngine.current.position.positionBaseAsset.profitLoss.value * 100 /
|
||||
tradingEngine.current.position.positionBaseAsset.entryTargetSize.value
|
||||
|
||||
tradingEngine.current.position.positionQuotedAsset.ROI.value =
|
||||
tradingEngine.current.position.positionQuotedAsset.profitLoss.value * 100 /
|
||||
tradingEngine.current.position.positionQuotedAsset.entryTargetSize.value
|
||||
|
||||
tradingEngine.current.position.positionBaseAsset.ROI.value = global.PRECISE(tradingEngine.current.position.positionBaseAsset.ROI.value, 10)
|
||||
tradingEngine.current.position.positionQuotedAsset.ROI.value = global.PRECISE(tradingEngine.current.position.positionQuotedAsset.ROI.value, 10)
|
||||
|
||||
/* Hit Fail Calculation */
|
||||
if (tradingEngine.current.position.positionBaseAsset.ROI.value > 0) {
|
||||
tradingEngine.current.position.positionBaseAsset.hitFail.value = 'Hit'
|
||||
} else {
|
||||
tradingEngine.current.position.positionBaseAsset.hitFail.value = 'Fail'
|
||||
}
|
||||
if (tradingEngine.current.position.positionQuotedAsset.ROI.value > 0) {
|
||||
tradingEngine.current.position.positionQuotedAsset.hitFail.value = 'Hit'
|
||||
} else {
|
||||
tradingEngine.current.position.positionQuotedAsset.hitFail.value = 'Fail'
|
||||
tradingEngine.current.position.positionStatistics.profitLoss.value = global.PRECISE(tradingEngine.current.position.positionStatistics.profitLoss.value, 10)
|
||||
|
||||
/* ROI Calculation */
|
||||
tradingEngine.current.position.positionStatistics.ROI.value =
|
||||
(
|
||||
tradingEngine.current.position.positionStatistics.profitLoss.value
|
||||
)
|
||||
* 100 /
|
||||
(
|
||||
tradingEngine.current.position.positionBaseAsset.beginBalance * tradingEngine.current.position.beginRate.value +
|
||||
tradingEngine.current.position.positionQuotedAsset.beginBalance
|
||||
)
|
||||
tradingEngine.current.position.positionStatistics.ROI.value = global.PRECISE(tradingEngine.current.position.positionStatistics.ROI.value, 10)
|
||||
|
||||
/* Hit Fail Calculation */
|
||||
if (tradingEngine.current.position.positionStatistics.ROI.value > 0) {
|
||||
tradingEngine.current.position.positionStatistics.hitFail.value = 'Hit'
|
||||
} else {
|
||||
tradingEngine.current.position.positionStatistics.hitFail.value = 'Fail'
|
||||
}
|
||||
|
||||
/* Days Calculation */
|
||||
tradingEngine.current.position.positionStatistics.days.value =
|
||||
tradingEngine.current.position.positionCounters.periods.value *
|
||||
sessionParameters.timeFrame.config.value / global.ONE_DAY_IN_MILISECONDS
|
||||
|
||||
tradingEngine.current.position.positionStatistics.days.value = global.PRECISE(tradingEngine.current.position.positionStatistics.days.value, 10)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -19,11 +19,11 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
|
||||
thisObject = undefined
|
||||
}
|
||||
|
||||
function runSimulation(
|
||||
async function runSimulation(
|
||||
chart,
|
||||
outputDatasetsMap,
|
||||
callback,
|
||||
callBackFunction) {
|
||||
writeFiles,
|
||||
) {
|
||||
try {
|
||||
|
||||
let tradingSystem = bot.simulationState.tradingSystem
|
||||
@@ -58,51 +58,54 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
|
||||
let heartBeatDate
|
||||
let previousHeartBeatDate
|
||||
let firstLoopExecution = true
|
||||
|
||||
/*
|
||||
Loop Initialization
|
||||
*/
|
||||
if (bot.FIRST_EXECUTION === false && tradingEngine.last.candle !== undefined) {
|
||||
/* Estimate the Initial Candle based on the last candle saved at tradingEngine */
|
||||
let firstBegin = candles[0].begin
|
||||
let lastBegin = tradingEngine.last.candle.begin
|
||||
let diff = lastBegin - firstBegin
|
||||
let amount = diff / sessionParameters.timeFrame.config.value
|
||||
|
||||
initializeLoop()
|
||||
tradingEngine.current.episode.candle.index.value = Math.trunc(amount) + 1 // Because we need to start from the next candle
|
||||
if (tradingEngine.current.episode.candle.index.value < 0 || tradingEngine.current.episode.candle.index.value > candles.length - 1) {
|
||||
logger.write(MODULE_NAME, '[ERROR] runSimulation -> initializeLoop -> Cannot resume simulation.')
|
||||
logger.write(MODULE_NAME, '[ERROR] runSimulation -> initializeLoop -> tradingEngine.current.episode.candle.index.value = ' + tradingEngine.current.episode.candle.index.value)
|
||||
logger.write(MODULE_NAME, '[ERROR] runSimulation -> initializeLoop -> firstBegin = ' + firstBegin)
|
||||
logger.write(MODULE_NAME, '[ERROR] runSimulation -> initializeLoop -> lastBegin = ' + lastBegin)
|
||||
logger.write(MODULE_NAME, '[ERROR] runSimulation -> initializeLoop -> diff = ' + diff)
|
||||
logger.write(MODULE_NAME, '[ERROR] runSimulation -> initializeLoop -> amount = ' + amount)
|
||||
|
||||
function initializeLoop() {
|
||||
if (bot.FIRST_EXECUTION === false && tradingEngine.last.candle !== undefined) {
|
||||
/* Estimate the Initial Candle based on the last candle saved at tradingEngine */
|
||||
let firstBegin = candles[0].begin
|
||||
let lastBegin = tradingEngine.last.candle.begin
|
||||
let diff = lastBegin - firstBegin
|
||||
let amount = diff / sessionParameters.timeFrame.config.value
|
||||
|
||||
tradingEngine.current.episode.candle.index.value = Math.trunc(amount) + 1 // Because we need to start from the next candle
|
||||
if (tradingEngine.current.episode.candle.index.value < 0 || tradingEngine.current.episode.candle.index.value > candles.length - 1) {
|
||||
logger.write(MODULE_NAME, '[ERROR] runSimulation -> initializeLoop -> Cannot resume simulation.')
|
||||
logger.write(MODULE_NAME, '[ERROR] runSimulation -> initializeLoop -> tradingEngine.current.episode.candle.index.value = ' + tradingEngine.current.episode.candle.index.value)
|
||||
logger.write(MODULE_NAME, '[ERROR] runSimulation -> initializeLoop -> firstBegin = ' + firstBegin)
|
||||
logger.write(MODULE_NAME, '[ERROR] runSimulation -> initializeLoop -> lastBegin = ' + lastBegin)
|
||||
logger.write(MODULE_NAME, '[ERROR] runSimulation -> initializeLoop -> diff = ' + diff)
|
||||
logger.write(MODULE_NAME, '[ERROR] runSimulation -> initializeLoop -> amount = ' + amount)
|
||||
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
/* Estimate Initial Candle based on the timeRage configured for the session. */
|
||||
let firstEnd = candles[0].end
|
||||
let targetEnd = sessionParameters.timeRange.config.initialDatetime
|
||||
let diff = targetEnd - firstEnd
|
||||
let amount = diff / sessionParameters.timeFrame.config.value
|
||||
|
||||
tradingEngine.current.episode.candle.index.value = Math.trunc(amount)
|
||||
if (tradingEngine.current.episode.candle.index.value < 0) { tradingEngine.current.episode.candle.index.value = 0 }
|
||||
if (tradingEngine.current.episode.candle.index.value > candles.length - 1) {
|
||||
/*
|
||||
This will happen when the sessionParameters.timeRange.config.initialDatetime is beyond the last candle available,
|
||||
meaning that the dataSet needs to be updated with more up-to-date data.
|
||||
*/
|
||||
tradingEngine.current.episode.candle.index.value = candles.length - 1
|
||||
}
|
||||
throw(global.DEFAULT_FAIL_RESPONSE)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
/* Estimate Initial Candle based on the timeRage configured for the session. */
|
||||
let firstEnd = candles[0].end
|
||||
let targetEnd = sessionParameters.timeRange.config.initialDatetime
|
||||
let diff = targetEnd - firstEnd
|
||||
let amount = diff / sessionParameters.timeFrame.config.value
|
||||
|
||||
loop()
|
||||
tradingEngine.current.episode.candle.index.value = Math.trunc(amount)
|
||||
if (tradingEngine.current.episode.candle.index.value < 0) { tradingEngine.current.episode.candle.index.value = 0 }
|
||||
if (tradingEngine.current.episode.candle.index.value > candles.length - 1) {
|
||||
/*
|
||||
This will happen when the sessionParameters.timeRange.config.initialDatetime is beyond the last candle available,
|
||||
meaning that the dataSet needs to be updated with more up-to-date data.
|
||||
*/
|
||||
tradingEngine.current.episode.candle.index.value = candles.length - 1
|
||||
}
|
||||
}
|
||||
|
||||
async function loop() {
|
||||
/*
|
||||
Main Simulation Loop
|
||||
*/
|
||||
let breakLoop = false
|
||||
for( let i = tradingEngine.current.episode.candle.index.value; i < candles.length; i++) {
|
||||
|
||||
tradingEngine.current.episode.candle.index.value = i
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Processing candle # ' + tradingEngine.current.episode.candle.index.value) }
|
||||
let candle = candles[tradingEngine.current.episode.candle.index.value] // This is the current candle the Simulation is working at.
|
||||
|
||||
@@ -119,19 +122,8 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
|
||||
firstLoopExecution = false
|
||||
}
|
||||
|
||||
if (checkLastCandle() === false) {
|
||||
closeEpisode('Last Candle Reached')
|
||||
return
|
||||
}
|
||||
|
||||
if (checkMinimunAndMaximunBalance() === false) {
|
||||
closeEpisode('Min or Max Balance Reached')
|
||||
return
|
||||
}
|
||||
|
||||
if (checkInitialAndFinalDatetime() === false) {
|
||||
controlLoop()
|
||||
return
|
||||
if (checkInitialDatetime() === false) {
|
||||
continue
|
||||
}
|
||||
|
||||
positionChartAtCurrentCandle()
|
||||
@@ -178,75 +170,61 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
|
||||
tradingEngineModule.setCurrentCycle('Second')
|
||||
await tradingSystemModule.run()
|
||||
|
||||
controlLoop()
|
||||
}
|
||||
|
||||
function controlLoop() {
|
||||
/* 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 this session.') }
|
||||
console.log('[INFO] runSimulation -> controlLoop -> We are going to stop here bacause we were requested to stop processing this session.')
|
||||
updateEpisode('Session Stopped')
|
||||
return
|
||||
breakLoop = true
|
||||
}
|
||||
|
||||
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.')
|
||||
updateEpisode('Task Stopped')
|
||||
return
|
||||
breakLoop = true
|
||||
}
|
||||
|
||||
if (tradingEngine.current.episode.candle.index.value + 1 < candles.length) {
|
||||
|
||||
/* Add new records to the process output */
|
||||
tradingRecordsModule.appendRecords('Second')
|
||||
|
||||
tradingEngine.current.episode.candle.index.value++
|
||||
|
||||
/*
|
||||
This will execute the next loop in the next iteration of the NodeJs event loop
|
||||
allowing for other callbacks to be executed. It also prevents the error
|
||||
'Maximum call stack size exceeded', since the call is not placed at the call stack.
|
||||
*/
|
||||
setImmediate(loop)
|
||||
} else {
|
||||
updateEpisode('All Candles Processed')
|
||||
if (checkFinalDatetime() === false) {
|
||||
closeEpisode('Final Datetime Reached')
|
||||
breakLoop = true
|
||||
}
|
||||
|
||||
if (checkLastCandle() === false) {
|
||||
updateEpisode('All Available Candles Processed')
|
||||
breakLoop = true
|
||||
}
|
||||
|
||||
if (checkMinimunAndMaximunBalance() === false) {
|
||||
closeEpisode('Min or Max Balance Reached')
|
||||
breakLoop = true
|
||||
}
|
||||
|
||||
/* Add new records to the process output */
|
||||
tradingRecordsModule.appendRecords('Second')
|
||||
|
||||
if (breakLoop === true) {break}
|
||||
}
|
||||
|
||||
tradingEngineModule.finalize()
|
||||
tradingSystemModule.finalize()
|
||||
tradingRecordsModule.finalize()
|
||||
tradingEpisodeModule.finalize()
|
||||
|
||||
tradingEngineModule = undefined
|
||||
tradingSystemModule = undefined
|
||||
tradingRecordsModule = undefined
|
||||
tradingEpisodeModule = undefined
|
||||
|
||||
await writeFiles()
|
||||
|
||||
function closeEpisode(exitType) {
|
||||
tradingEpisodeModule.updateExitType(exitType)
|
||||
tradingEpisodeModule.closeEpisode()
|
||||
|
||||
/* Add new records to the process output */
|
||||
tradingRecordsModule.appendRecords('Second')
|
||||
|
||||
afterLoop()
|
||||
}
|
||||
|
||||
function updateEpisode(exitType) {
|
||||
tradingEpisodeModule.updateExitType(exitType)
|
||||
|
||||
/* Add new records to the process output */
|
||||
tradingRecordsModule.appendRecords('Second')
|
||||
|
||||
afterLoop()
|
||||
}
|
||||
|
||||
function afterLoop() {
|
||||
|
||||
tradingEngineModule.finalize()
|
||||
tradingSystemModule.finalize()
|
||||
tradingRecordsModule.finalize()
|
||||
tradingEpisodeModule.finalize()
|
||||
|
||||
tradingEngineModule = undefined
|
||||
tradingSystemModule = undefined
|
||||
tradingRecordsModule = undefined
|
||||
tradingEpisodeModule = undefined
|
||||
|
||||
callback()
|
||||
}
|
||||
|
||||
function heartBeat() {
|
||||
@@ -368,7 +346,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, '[ERROR] runSimulation -> getElement -> datasetName = ' + datasetName)
|
||||
logger.write(MODULE_NAME, '[ERROR] runSimulation -> getElement -> err = ' + err.stack)
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
|
||||
throw(global.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,7 +357,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
|
||||
*/
|
||||
if (bot.processingDailyFiles) { // We are processing Daily Files
|
||||
let candlesPerDay = global.ONE_DAY_IN_MILISECONDS / sessionParameters.timeFrame.config.value
|
||||
if (tradingEngine.current.episode.candle.index.value === candles.length - 1) {
|
||||
if (tradingEngine.current.episode.candle.index.value + 1 === candles.length - 1) {
|
||||
if ((candles.length < candlesPerDay) || (candles.length > candlesPerDay && candles.length < candlesPerDay * 2)) {
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> checkLastCandle -> Skipping Candle because it is the last one and has not been closed yet.') }
|
||||
return false
|
||||
@@ -390,7 +368,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
|
||||
}
|
||||
}
|
||||
} else { // We are processing Market Files
|
||||
if (tradingEngine.current.episode.candle.index.value === candles.length - 1) {
|
||||
if (tradingEngine.current.episode.candle.index.value + 1 === candles.length - 1) {
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> checkLastCandle -> Skipping Candle because it is the last one and has not been closed yet.') }
|
||||
return false
|
||||
}
|
||||
@@ -398,13 +376,18 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
|
||||
return true
|
||||
}
|
||||
|
||||
function checkInitialAndFinalDatetime() {
|
||||
/* Here we check that the current candle is not outside of user-defined time range at the session parameters.*/
|
||||
function checkInitialDatetime() {
|
||||
/* Here we check that the current candle is not before the initial datetime defined at the session parameters.*/
|
||||
if (tradingEngine.current.episode.candle.end.value < sessionParameters.timeRange.config.initialDatetime) {
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> checkInitialAndFinalDatetime -> Skipping Candle before the sessionParameters.timeRange.config.initialDatetime.') }
|
||||
return false
|
||||
}
|
||||
if (tradingEngine.current.episode.candle.begin.value > sessionParameters.timeRange.config.finalDatetime) {
|
||||
return true
|
||||
}
|
||||
|
||||
function checkFinalDatetime() {
|
||||
/* Here we check that the next candle is not after of the user-defined final datetime at the session parameters.*/
|
||||
if (tradingEngine.current.episode.candle.begin.value + sessionParameters.timeFrame.config.value > sessionParameters.timeRange.config.finalDatetime) {
|
||||
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> checkInitialAndFinalDatetime -> Skipping Candle after the sessionParameters.timeRange.config.finalDatetime.') }
|
||||
return false
|
||||
}
|
||||
@@ -464,7 +447,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write(MODULE_NAME, '[ERROR] runSimulation -> err = ' + err.stack)
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
|
||||
throw(global.DEFAULT_FAIL_RESPONSE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
|
||||
updateChart: updateChart,
|
||||
mantain: mantain,
|
||||
reset: reset,
|
||||
calculateStatistics: calculateStatistics,
|
||||
runTriggerStage: runTriggerStage,
|
||||
runOpenStage: runOpenStage,
|
||||
runManageStage: runManageStage,
|
||||
@@ -101,6 +102,11 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
|
||||
resetTradingEngineDataStructure()
|
||||
}
|
||||
|
||||
function calculateStatistics() {
|
||||
tradingEpisodeModule.calculateStatistics()
|
||||
tradingPositionModule.calculateStatistics()
|
||||
}
|
||||
|
||||
function runTriggerStage() {
|
||||
/*
|
||||
We check if we will be triggering on, off or taking position.
|
||||
@@ -870,9 +876,6 @@ exports.newTradingStages = function newTradingStages(bot, logger, tradingEngineM
|
||||
/* Close the Position */
|
||||
tradingPositionModule.closePosition()
|
||||
|
||||
tradingEpisodeModule.calculateResults()
|
||||
tradingEpisodeModule.calculateStatistics()
|
||||
|
||||
/* Close the Strategy */
|
||||
tradingStrategyModule.closeStrategy('Position Closed')
|
||||
|
||||
|
||||
@@ -131,6 +131,9 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM
|
||||
|
||||
/* Run the Close Stage */
|
||||
await tradingStagesModule.runCloseStage()
|
||||
|
||||
tradingStagesModule.calculateStatistics()
|
||||
|
||||
} catch (err) {
|
||||
/*
|
||||
If an error ocurred during execution, it was alreeady logged and
|
||||
|
||||
@@ -490,7 +490,7 @@
|
||||
function writeDataRange(pBegin, pEnd, productCodeName, callBack) {
|
||||
let dataRange = {
|
||||
begin: pBegin.valueOf(),
|
||||
end: pEnd.valueOf()
|
||||
end: pEnd.valueOf() + ONE_DAY_IN_MILISECONDS
|
||||
};
|
||||
let fileContent = JSON.stringify(dataRange)
|
||||
let fileName = '/Data.Range.json';
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
let bot = BOT;
|
||||
|
||||
let thisObject = {
|
||||
raiseEvents, raiseEvents
|
||||
raiseEvents: raiseEvents,
|
||||
asyncRaiseEvents: asyncRaiseEvents
|
||||
};
|
||||
|
||||
return thisObject;
|
||||
@@ -99,4 +100,70 @@
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function asyncRaiseEvents(lastFile, timeFrames) {
|
||||
|
||||
if (bot.processNode.referenceParent.processOutput !== undefined) {
|
||||
if (bot.processNode.referenceParent.processOutput.outputDatasets !== undefined) {
|
||||
let outputDatasets = bot.processNode.referenceParent.processOutput.outputDatasets
|
||||
|
||||
for (let j = 0; j < outputDatasets.length; j++) {
|
||||
let outputDataset = outputDatasets[j]
|
||||
|
||||
/* Some validations to verify that everything is in place. */
|
||||
if (outputDataset.referenceParent !== undefined) {
|
||||
if (outputDataset.referenceParent.config.codeName === undefined) {
|
||||
logger.write(MODULE_NAME, "[ERROR] raiseEvents -> codeName at Dataset Definition not defined. Dataset Definition = " + JSON.stringify(outputDataset.referenceParent));
|
||||
throw(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
if (outputDataset.referenceParent.parentNode !== undefined) {
|
||||
if (outputDataset.referenceParent.parentNode.config.codeName === undefined) {
|
||||
logger.write(MODULE_NAME, "[ERROR] raiseEvents -> codeName at Product not defined. Product = " + JSON.stringify(outputDataset.referenceParent.parentNode));
|
||||
throw(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
if (outputDataset.referenceParent.parentNode.parentNode !== undefined) {
|
||||
if (outputDataset.referenceParent.parentNode.parentNode.config.codeName === undefined) {
|
||||
logger.write(MODULE_NAME, "[ERROR] raiseEvents -> codeName at Bot not defined. Bot = " + JSON.stringify(outputDataset.referenceParent.parentNode.parentNode));
|
||||
throw(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
if (outputDataset.referenceParent.parentNode.parentNode.parentNode !== undefined) {
|
||||
if (outputDataset.referenceParent.parentNode.parentNode.parentNode.config.codeName === undefined) {
|
||||
logger.write(MODULE_NAME, "[ERROR] raiseEvents -> codeName at Data Mine not defined. Data Mine = " + JSON.stringify(outputDataset.referenceParent.parentNode.parentNode.parentNode));
|
||||
throw(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
} else {
|
||||
logger.write(MODULE_NAME, "[ERROR] raiseEvents -> Bot not attached to a Data Mine. Bot = " + JSON.stringify(outputDataset.referenceParent.parentNode.parentNode));
|
||||
throw(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
} else {
|
||||
logger.write(MODULE_NAME, "[ERROR] raiseEvents -> Product not attached to a Bot. Product = " + JSON.stringify(outputDataset.referenceParent.parentNode));
|
||||
throw(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
} else {
|
||||
logger.write(MODULE_NAME, "[ERROR] raiseEvents -> Dataset Definition not attached to a Product. Dataset Definition = " + JSON.stringify(outputDataset.referenceParent));
|
||||
throw(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
} else {
|
||||
logger.write(MODULE_NAME, "[ERROR] raiseEvents -> Output Dataset with no reference to a Dataset Definition. Output Dataset = " + JSON.stringify(outputDataset));
|
||||
throw(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
|
||||
/* All good, lets emit the event. */
|
||||
|
||||
let dataMine = outputDataset.referenceParent.parentNode.parentNode.parentNode.config.codeName
|
||||
let botName = outputDataset.referenceParent.parentNode.parentNode.config.codeName
|
||||
let product = outputDataset.referenceParent.parentNode.config.codeName
|
||||
let dataset = outputDataset.referenceParent.config.codeName
|
||||
|
||||
key = dataMine + "-" + botName + "-" + product + "-" + dataset + "-" + bot.exchange + "-" + bot.market.baseAsset + '/' + bot.market.quotedAsset
|
||||
let event = {
|
||||
lastFile: lastFile,
|
||||
timeFrames: timeFrames
|
||||
}
|
||||
global.EVENT_SERVER_CLIENT.createEventHandler(key, 'Dataset Updated')
|
||||
global.EVENT_SERVER_CLIENT.raiseEvent(key, 'Dataset Updated', event)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
+16
-10
@@ -22,9 +22,9 @@
|
||||
|
||||
/* Set the folderName for early logging */
|
||||
if (bot.processNode.session.config.folderName === undefined) {
|
||||
bot.SESSION.folderName = bot.SESSION.id
|
||||
bot.SESSION.folderName = bot.processNode.session.type.replace(' ', '-').replace(' ', '-') + '-' + bot.SESSION.id
|
||||
} else {
|
||||
bot.SESSION.folderName = bot.processNode.session.config.folderName + "-" + bot.SESSION.id
|
||||
bot.SESSION.folderName = bot.processNode.session.type.replace(' ', '-').replace(' ', '-') + '-' + bot.processNode.session.config.folderName
|
||||
}
|
||||
|
||||
/* Check if there is a session */
|
||||
@@ -125,14 +125,18 @@
|
||||
}
|
||||
|
||||
function setUpSessionFolderName() {
|
||||
/* Set the folderName for logging, reports, context and data output */
|
||||
/*
|
||||
The session object is overwritten when the session is run. For that reason we
|
||||
need to setup again the folder name at the Session level.
|
||||
Set the folderName for logging, reports, context and data output
|
||||
*/
|
||||
let config
|
||||
if (bot.SESSION.config !== undefined) {
|
||||
config = bot.SESSION.config
|
||||
if (config.folderName === undefined) {
|
||||
bot.SESSION.folderName = bot.SESSION.id
|
||||
bot.SESSION.folderName = bot.processNode.session.type.replace(' ', '-').replace(' ', '-') + '-' + bot.SESSION.id
|
||||
} else {
|
||||
bot.SESSION.folderName = config.folderName + "-" + bot.SESSION.id
|
||||
bot.SESSION.folderName = bot.processNode.session.type.replace(' ', '-').replace(' ', '-') + '-' + bot.processNode.session.config.folderName
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -162,11 +166,13 @@
|
||||
}
|
||||
} else {
|
||||
/* Check that we received valid dates */
|
||||
if(isNaN(new Date(bot.SESSION.parameters.timeRange.config.initialDatetime)).valueOf()) {
|
||||
let errorMessage = "sessionParameters.timeRange.config.initialDatetime is not a valid date."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION.parameters, errorMessage)
|
||||
return false
|
||||
if (bot.SESSION.type === 'Backtesting Session') {
|
||||
if(isNaN(new Date(bot.SESSION.parameters.timeRange.config.initialDatetime)).valueOf()) {
|
||||
let errorMessage = "sessionParameters.timeRange.config.initialDatetime is not a valid date."
|
||||
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> checkParemeters -> " + errorMessage)
|
||||
bot.sessionError(bot.SESSION.parameters, errorMessage)
|
||||
return false
|
||||
}
|
||||
}
|
||||
if(isNaN(new Date(bot.SESSION.parameters.timeRange.config.finalDatetime)).valueOf()) {
|
||||
let errorMessage = "sessionParameters.timeRange.config.initialDatetime is not a valid date."
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
finalize: finalize,
|
||||
load: load,
|
||||
save: save,
|
||||
asyncSave: asyncSave,
|
||||
status: undefined
|
||||
};
|
||||
|
||||
@@ -343,4 +344,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
async function asyncSave() {
|
||||
|
||||
let fileName = "Status.Report.json";
|
||||
let filePath = bot.filePathRoot + "/Reports/" + sessionPath + statusDependencyNode.process;
|
||||
|
||||
filePath += '/' + fileName
|
||||
let fileContent = JSON.stringify(thisObject.file);
|
||||
|
||||
let response = await fileStorage.asyncCreateTextFile(filePath, fileContent + '\n', true)
|
||||
|
||||
if (response.err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
throw(response.err)
|
||||
}
|
||||
|
||||
/* All good, lets emit the event that means data has been updated. */
|
||||
let processOutput = PROCESS_OUTPUT.newProcessOutput(bot, logger)
|
||||
processOutput.asyncRaiseEvents(thisObject.file.lastFile, thisObject.file.timeFrames)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user