Paper Trading Fixed

This commit is contained in:
Luis Fernando Molina committed 2020-08-21 10:14:12 +02:00
1 parent da25a3b8f6
commit 7469c58e0e
13 files changed
+678 -590

No files matched your search

@@ -65,6 +65,7 @@ exports.newTradingEngine = function newTradingEngine(bot, logger) {
}
function setCurrentCycle(cycle) {
tradingEngine.current.episode.cycle.value = cycle
switch (cycle) {
case 'First': {
tradingEngine.current.episode.cycle.begin.value =
@@ -269,7 +269,6 @@ exports.newTradingEpisode = function newTradingEpisode(bot, logger, tradingEngin
}
}
function updateDistanceToEventsCounters() {
/* Keeping Distance Counters Up-to-date while avoinding counting before the first event happens. */
if (
+24 -12
View File
@@ -117,7 +117,9 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
switch (tradingEngineOrder.status.value) {
case 'Not Open': {
{
{
/* During the First cycle we can not create new orders. That is reserved for the Second cycle. */
if (tradingEngine.current.episode.cycle.value === 'First') {continue}
/* When the stage is closing we can not create new orders */
if (tradingEngineStage.status.value === 'Closing') { continue }
/*
@@ -147,13 +149,15 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
/* Check Events that happens at the Exchange, if needed. */
await checkExchangeEvents(tradingEngineStage, tradingSystemOrder, tradingEngineOrder)
/* During the Second cycle we can not cancel orders. That is reserved for the First cycle. */
if (tradingEngine.current.episode.cycle.value === 'Second') {continue}
/*
In the previous steps, we might have discovered that the order was cancelled
at the exchange, or filled, so the order might still not be Open.
If the stage is closing or the order is not Open, we wont be cancelling orders
based on defined events.
*/
if (tradingEngineStage.status.value !== 'Closing' && tradingEngineOrder.status.value === 'Open') {
if (tradingEngineStage.status.value !== 'Closing' && tradingEngineOrder.status.value === 'Open') {
/* Check if we need to Cancel this Order */
let situationName = checkOrderEvent(tradingSystemOrder.cancelOrderEvent, tradingSystemOrder, executionAlgorithm, executionNode)
@@ -239,20 +243,27 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
tradingEngineOrder.situationName.value = situationName
function calculateOrderRate() {
/* By default this is the order rate and it is the rate that applies to Market Orders */
tradingEngineOrder.rate.value = tradingEngine.current.episode.candle.close.value
/* Optional Rate Definition */
if (tradingSystemOrder.orderRate !== undefined) {
if (tradingSystemOrder.orderRate.formula !== undefined) {
tradingEngineOrder.rate.value = tradingSystem.formulas.get(tradingSystemOrder.orderRate.formula.id)
if (tradingSystemOrder.type === 'Limit Buy Order' || tradingSystemOrder.type === 'Limit Sell Order') {
if (tradingSystemOrder.orderRate === undefined) { badDefinitionUnhandledException(undefined, 'tradingSystemOrder.orderRate === undefined', tradingSystemOrder) }
if (tradingSystemOrder.orderRate.formula === undefined) { badDefinitionUnhandledException(undefined, 'tradingSystemOrder.orderRate.formula === undefined', tradingSystemOrder) }
/* Extract the rate value from the user-defined formula */
tradingEngineOrder.rate.value = tradingSystem.formulas.get(tradingSystemOrder.orderRate.formula.id)
if (tradingEngineOrder.rate.value === undefined) { badDefinitionUnhandledException(undefined, 'tradingEngineOrder.rate.value === undefined', tradingEngineOrder) }
if (isNaN(tradingEngineOrder.rate.value) === true) { badDefinitionUnhandledException(undefined, 'isNaN(tradingEngineOrder.rate.value) === true', tradingEngineOrder) }
if (tradingEngineOrder.rate.value <= 0) { badDefinitionUnhandledException(undefined, 'tradingEngineOrder.rate.value <= 0', tradingEngineOrder) }
/* Final rate validations */
if (tradingEngineOrder.rate.value === undefined) { badDefinitionUnhandledException(undefined, 'tradingEngineOrder.rate.value === undefined', tradingSystemOrder) }
if (isNaN(tradingEngineOrder.rate.value) === true) { badDefinitionUnhandledException(undefined, 'isNaN(tradingEngineOrder.rate.value) === true', tradingSystemOrder) }
if (tradingEngineOrder.rate.value <= 0) { badDefinitionUnhandledException(undefined, 'tradingEngineOrder.rate.value <= 0', tradingSystemOrder) }
tradingEngineOrder.rate.value = global.PRECISE(tradingEngineOrder.rate.value, 10)
}
tradingEngineOrder.rate.value = global.PRECISE(tradingEngineOrder.rate.value, 10)
} else {
/*
For Market Orders, the rate is irrelevant, since it is not sent to the Exchange.
We store at this field the last know price as a reference.
*/
tradingEngineOrder.rate.value = tradingEngine.current.episode.candle.close.value
}
}
@@ -293,6 +304,7 @@ exports.newTradingOrders = function newTradingOrders(bot, logger, tradingEngineM
/* Size in Quoted Asset */
tradingEngineOrder.orderQuotedAsset.size.value = algorithmSizeInQuotedAsset * tradingSystemOrder.config.percentageOfAlgorithmSize / 100
/* Check that the Size calculated would not surpass Stage Target Size */
if (
tradingEngineOrder.orderQuotedAsset.size.value + tradingEngineStage.stageQuotedAsset.sizePlaced.value >
tradingEngineStage.stageQuotedAsset.targetSize.value
@@ -1,4 +1,4 @@
exports.newTradingOutput = function newTradingOutput(bot, logger, UTILITIES, FILE_STORAGE) {
exports.newTradingOutput = function newTradingOutput(bot, logger, tradingEngineModule, UTILITIES, FILE_STORAGE) {
/*
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.
@@ -27,7 +27,7 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, UTILITIES, FIL
}
async function start(chart, timeFrame, timeFrameLabel, currentDay) {
async function start(chart, timeFrame, timeFrameLabel, tradingProcessDate) {
try {
if (timeFrame > global.dailyFilePeriods[0][0]) {
@@ -38,18 +38,12 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, UTILITIES, FIL
/* Preparing everything for the Simulation */
const TRADING_SIMULATION = require('./TradingSimulation.js')
let tradingSimulation = TRADING_SIMULATION.newTradingSimulation(bot, logger, UTILITIES)
let tradingSimulation = TRADING_SIMULATION.newTradingSimulation(bot, logger, tradingEngineModule, UTILITIES)
let outputDatasets = bot.processNode.referenceParent.processOutput.outputDatasets
let market = bot.market
let outputDatasetsMap = new Map()
if (bot.FIRST_EXECUTION === true && bot.RESUME === false) {
/*
Here is where the Trading Engine and Trading Systems received are moved to the simulation state.
*/
bot.simulationState.tradingEngine = bot.TRADING_ENGINE
bot.simulationState.tradingSystem = bot.TRADING_SYSTEM
await initializeOutputs()
} else {
await readFiles()
@@ -60,6 +54,8 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, UTILITIES, FIL
outputDatasetsMap,
writeFiles
)
tradingSimulation.finalize()
return
async function initializeOutputs() {
@@ -127,7 +123,7 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, UTILITIES, FIL
if (dataset.config.type === 'Daily Files') {
let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2);
let dateForPath = tradingProcessDate.getUTCFullYear() + '/' + utilities.pad(tradingProcessDate.getUTCMonth() + 1, 2) + '/' + utilities.pad(tradingProcessDate.getUTCDate(), 2);
let fileName = 'Data.json'
let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel + "/" + dateForPath
@@ -184,7 +180,7 @@ exports.newTradingOutput = function newTradingOutput(bot, logger, UTILITIES, FIL
if (dataset.config.type === 'Daily Files') {
let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2);
let dateForPath = tradingProcessDate.getUTCFullYear() + '/' + utilities.pad(tradingProcessDate.getUTCMonth() + 1, 2) + '/' + utilities.pad(tradingProcessDate.getUTCDate(), 2);
let fileName = 'Data.json'
let filePath = bot.filePathRoot + '/Output/' + bot.SESSION.folderName + '/' + dataset.parentNode.config.codeName + '/' + dataset.config.codeName + '/' + timeFrameLabel + "/" + dateForPath
+166 -166
View File
@@ -1,4 +1,4 @@
exports.newTradingProcess = function newTradingProcess(bot, logger, UTILITIES, TRADING_OUTPUT_MODULE, USER_BOT_COMMONS) {
exports.newTradingProcess = function newTradingProcess(bot, logger, UTILITIES) {
/*
This Module will load all the process data dependencies from files and send them downstream.
After execution, will save the time range and status report of the process.
@@ -20,11 +20,15 @@
let dataFiles = new Map();
let multiPeriodDataFiles = new Map();
let tradingOutputModule;
const FILE_STORAGE = require('../FileStorage.js');
let fileStorage = FILE_STORAGE.newFileStorage(logger);
const TRADING_ENGINE_MODULE = require('./TradingEngine.js')
let tradingEngineModule = TRADING_ENGINE_MODULE.newTradingEngine(bot, logger)
let TRADING_OUTPUT_MODULE = require("./TradingOutput")
let tradingOutputModule = TRADING_OUTPUT_MODULE.newTradingOutput(bot, logger, tradingEngineModule, UTILITIES, FILE_STORAGE)
let processConfig;
return thisObject;
@@ -38,8 +42,6 @@
dataDependenciesModule = pDataDependencies
processConfig = pProcessConfig
let TRADING_OUTPUT_MODULE = require("./TradingOutput")
tradingOutputModule = TRADING_OUTPUT_MODULE.newTradingOutput(bot, logger, UTILITIES, FILE_STORAGE)
tradingOutputModule.initialize()
callBackFunction(global.DEFAULT_OK_RESPONSE)
@@ -51,12 +53,17 @@
}
function finalize() {
tradingEngineModule.finalize()
tradingEngineModule = undefined
tradingOutputModule.finalize()
tradingOutputModule = undefined
dataFiles = undefined
multiPeriodDataFiles = undefined
statusDependencies = undefined
dataDependenciesModule = undefined
tradingOutputModule.finalize()
tradingOutputModule = undefined
fileStorage = undefined
processConfig = undefined
thisObject = undefined
@@ -66,22 +73,58 @@
try {
let currentTimeFrame
let currentTimeFrameLabel
let market = bot.market;
/* Context Variables */
let contextVariables = {
lastFile: undefined, // Datetime of the last file files sucessfully produced by this process.
dateBeginOfMarket: undefined, // Datetime of the first trade file in the whole market history.
dateEndOfMarket: undefined // Datetime of the last file available to be used as an input of this process.
};
let previousDay; // Holds the date of the previous day relative to the processing date.
getContextVariables()
if (bot.FIRST_EXECUTION === true && bot.RESUME === false) {
/*
Here is where the Trading Engine and Trading Systems received are moved to the simulation state.
*/
bot.simulationState.tradingEngine = bot.TRADING_ENGINE
bot.simulationState.tradingSystem = bot.TRADING_SYSTEM
}
/* We set up the Trading Engine Module. */
tradingEngineModule.initialize()
/* Initializing the Trading Process Date */
if (bot.FIRST_EXECUTION === true && bot.RESUME === false) {
/*
This funcion is going to be called many times by the Trading Bot Loop.
Only during the first execution and when the User is not resuming the execution
of a stopped session / task; we are going to initialize the Process Date Time.
This variable tell us which day we are standing at, specially while working
with Daily Files. From this Date is that we are going to load the Daily Files.
*/
bot.simulationState.tradingEngine.current.episode.processDate.value = global.REMOVE_TIME(bot.SESSION.parameters.timeRange.config.initialDatetime).valueOf()
}
/*
This is the Date that is going to be used across the execution of this Trading Process.
We need this because it has a different life cycle than the processData stored at the
Trading Engine data structure. This date has to remain the same during the whole execution
of the Trading Process until the end, inclusind the writting of Data Ranges and Status Reports.
The processDate of the Trading Engine data structure on the other hand can be changed during
the simulation loop, once we discover that all candles from a certain date have benn processed.
Here is the point where we sync one and the other.
*/
let tradingProcessDate = global.REMOVE_TIME(bot.simulationState.tradingEngine.current.episode.processDate.value)
await processSingleFiles()
await processMarketFiles()
/*
This is the Data Structure used at the Simulation with all indicator data.
We start creating it right here.
*/
let chart = {}
/*
Here we check if we need to get Daily Files or not. As an optimization, when
we are running on a Time Frame of 1hs or above, we are not going to load
@@ -89,54 +132,56 @@
we alreaady set a value to currentTimeFrame. We are also not going to loop
through days if we are processing market files.
*/
if (currentTimeFrame) {
/* We are processing Market Files */
let chart = {}
buildCharts(chart)
await generateOutput(chart)
await writeProcessFiles()
checkIfSessionMustStop()
} else {
/* We are processing Daily Files */
/*
Go back one day to start well when we advance time at the begining of the loop.
*/
bot.tradingProcessDate = new Date(contextVariables.lastFile.valueOf() - global.ONE_DAY_IN_MILISECONDS);
do {
if (advanceTime() === false) {break}
if (checkStopTaskGracefully() === false) {break}
if (checkStopProcessing() === false) {break}
/*
We update the Trading Process Date with the date calculated at the simulation.
We will use this date to load indicator and output files. After that we will
use it to save Output Files and later the Data Ranges. This is the point where
the date calculated by the Simulation is applied at the Trading Process Level.
*/
tradingProcessDate = global.REMOVE_TIME(bot.simulationState.tradingEngine.current.episode.processDate.value)
await processDailyFiles()
let chart = {}
buildCharts(chart)
await generateOutput(chart)
await writeProcessFiles()
if (checkStopHeadOfTheMarket() === false) {break}
}
while (true)
}
checkIfSessionMustStop()
/*
Everything worked as expected. We return an OK code and wait for
the Bot Loop to call us again later.
*/
callBackFunction(global.DEFAULT_OK_RESPONSE)
function getContextVariables() {
try {
let thisReport;
let reportKey;
let statusReport;
/* We are going to use the start date as beging of market date. */
contextVariables.dateBeginOfMarket = new Date(bot.SESSION.parameters.timeRange.config.initialDatetime)
contextVariables.dateBeginOfMarket = global.REMOVE_TIME(bot.SESSION.parameters.timeRange.config.initialDatetime)
/*
Here we get the status report from the bot who knows which is the end of the market.
Here we get the status report from the bot who knows which is the end of the market.
*/
statusReport = statusDependencies.reportsByMainUtility.get("Market Ending Point")
@@ -168,17 +213,6 @@
contextVariables.dateEndOfMarket = new Date(thisReport.lastFile.valueOf());
/* Validation that the data is not up-to-date. */
if (bot.tradingProcessDate.valueOf() - global.ONE_DAY_IN_MILISECONDS > contextVariables.dateEndOfMarket.valueOf() && bot.SESSION.type !== "Backtesting Session") {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> " + "Head of the market is @ " + contextVariables.dateEndOfMarket); }
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> You need to UPDATE your datasets in order to run a " + bot.SESSION.type) }
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return
}
/* Finally we get our own Status Report. */
statusReport = statusDependencies.reportsByMainUtility.get("Self Reference")
@@ -254,29 +288,13 @@
/* We cut the async calls via callBacks at this point, so as to have a clearer code upstream */
let response = await asyncGetDatasetFile(datasetModule, filePath, fileName)
onFileReceived(response.err, response.text)
function onFileReceived(err, text) {
try {
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
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 -> processSingleFiles -> onFileReceived -> err = " + err.message);
callBackFunction(err);
}
return
}
let dataFile = JSON.parse(text);
dataFiles.set(dependency.id, dataFile);
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processSingleFiles -> onFileReceived -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
if (response.err.result !== global.DEFAULT_OK_RESPONSE.result) {
throw(response.err)
}
let dataFile = JSON.parse(response.text);
dataFiles.set(dependency.id, dataFile);
}
let mapKey = "Single Files"
@@ -319,30 +337,14 @@
/* We cut the async calls via callBacks at this point, so as to have a clearer code upstream */
let response = await asyncGetDatasetFile(datasetModule, filePath, fileName)
onFileReceived(response.err, response.text)
function onFileReceived(err, text) {
try {
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
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 -> processMarketFiles -> onFileReceived -> err = " + err.message);
callBackFunction(err);
}
return
}
let dataFile = JSON.parse(text);
let trimmedDataFile = trimDataFile(dataFile, datasetModule.node.parentNode.record)
dataFiles.set(dependency.id, trimmedDataFile);
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processMarketFiles -> onFileReceived -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
if (response.err.result !== global.DEFAULT_OK_RESPONSE.result) {
throw(response.err)
}
let dataFile = JSON.parse(response.text);
let trimmedDataFile = trimDataFile(dataFile, datasetModule.node.parentNode.record)
dataFiles.set(dependency.id, trimmedDataFile);
function trimDataFile(dataFile, recordDefinition) {
/*
@@ -379,8 +381,8 @@
async function processDailyFiles() {
/* Telling the world we are alive and doing well and which date we are processing right now. */
let processingDate = bot.tradingProcessDate.getUTCFullYear() + '-' + utilities.pad(bot.tradingProcessDate.getUTCMonth() + 1, 2) + '-' + utilities.pad(bot.tradingProcessDate.getUTCDate(), 2);
bot.processHeartBeat(processingDate)
let processingDateString = tradingProcessDate.getUTCFullYear() + '-' + utilities.pad(tradingProcessDate.getUTCMonth() + 1, 2) + '-' + utilities.pad(tradingProcessDate.getUTCDate(), 2);
bot.processHeartBeat(processingDateString)
/*
We will iterate through all posible timeFrames.
@@ -407,10 +409,13 @@
dataFiles = new Map();
/*
We will iterate through all dependencies, in order to load the
files that later will end up at the chart data structure.
*/
for (let dependencyIndex = 0; dependencyIndex < dataDependenciesModule.nodeArray.length; dependencyIndex++) {
let dependency = dataDependenciesModule.nodeArray[dependencyIndex];
let datasetModule = dataDependenciesModule.dataSetsModulesArray[dependencyIndex];
let file
if (dependency.referenceParent.config.codeName !== "Multi-Period-Daily") {
continue
@@ -422,7 +427,7 @@
}
}
let dateForPath = bot.tradingProcessDate.getUTCFullYear() + '/' + utilities.pad(bot.tradingProcessDate.getUTCMonth() + 1, 2) + '/' + utilities.pad(bot.tradingProcessDate.getUTCDate(), 2);
let dateForPath = tradingProcessDate.getUTCFullYear() + '/' + utilities.pad(tradingProcessDate.getUTCMonth() + 1, 2) + '/' + utilities.pad(tradingProcessDate.getUTCDate(), 2);
let filePath
if (dependency.referenceParent.config.codeName === "Multi-Period-Daily") {
filePath = dependency.referenceParent.parentNode.config.codeName + '/' + dependency.referenceParent.config.codeName + "/" + timeFrameLabel + "/" + dateForPath;
@@ -433,66 +438,32 @@
/* We cut the async calls via callBacks at this point, so as to have a clearer code upstream */
let response = await asyncGetDatasetFile(datasetModule, filePath, fileName)
onFileReceived(response.err, response.text)
function onFileReceived(err, text) {
try {
if ((err.result === "Fail Because" && err.message === "File does not exist.") || err.code === 'The specified key 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);
return
}
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] start -> processDailyFiles -> onFileReceived -> Not Ok -> err = " + err.code);
callBackFunction(err);
return
}
file = JSON.parse(text);
dataFiles.set(dependency.id, file);
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processDailyFiles -> onFileReceived -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
if (response.err.result !== global.DEFAULT_OK_RESPONSE.result) {
throw(response.err)
}
let dataFile = JSON.parse(response.text);
dataFiles.set(dependency.id, dataFile);
}
let mapKey = global.dailyFilePeriods[n][1];
multiPeriodDataFiles.set(mapKey, dataFiles)
}
if (currentTimeFrame !== undefined) {
buildCharts(advanceTime);
} else {
logger.write(MODULE_NAME, "[ERROR] start -> processDailyFiles -> Time Frame not Recognized. Can not continue.");
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function advanceTime() {
bot.tradingProcessDate = new Date(bot.tradingProcessDate.valueOf() + global.ONE_DAY_IN_MILISECONDS);
previousDay = new Date(bot.tradingProcessDate.valueOf() - global.ONE_DAY_IN_MILISECONDS);
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> advanceTime -> bot.tradingProcessDate = " + bot.tradingProcessDate); }
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> advanceTime -> previousDay = " + previousDay); }
/* Validation that we are not going past the user defined end date. */
if (bot.tradingProcessDate.valueOf() >= bot.SESSION.parameters.timeRange.config.finalDatetime) {
const logText = "User Defined End Datetime reached @ " + previousDay.getUTCFullYear() + "/" + (previousDay.getUTCMonth() + 1) + "/" + previousDay.getUTCDate() + ".";
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> advanceTime -> " + logText); }
bot.SESSION.stop(logText)
return false
}
/* Validation that we are not going past the head of the market. */
if (bot.tradingProcessDate.valueOf() > contextVariables.dateEndOfMarket.valueOf() + global.ONE_DAY_IN_MILISECONDS - 1) {
const logText = "Head of the market found @ " + previousDay.getUTCFullYear() + "/" + (previousDay.getUTCMonth() + 1) + "/" + previousDay.getUTCDate() + ".";
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> advanceTime -> " + logText); }
function checkStopHeadOfTheMarket() {
/*
We need to check if we have reached the head of the market in order to know
when to break the Daily Files Process loop and give time for a new candles /
indicators to be built and continue the processing once this process is called
again.
*/
if (bot.simulationState.tradingEngine.current.episode.headOfTheMarket.value === true) {
console.log('YES at the head of the market')
return false
}
console.log('NOT at the head of the market')
}
function checkStopTaskGracefully() {
@@ -566,7 +537,7 @@
chart,
currentTimeFrame,
currentTimeFrameLabel,
bot.tradingProcessDate
tradingProcessDate
)
bot.FIRST_EXECUTION = false // From here on, all other loops executions wont be the first execution.
@@ -575,24 +546,28 @@
async function writeProcessFiles() {
await writeTimeFramesFiles(currentTimeFrame, currentTimeFrameLabel)
await writeDataRanges(currentTimeFrameLabel)
await writeDataRanges()
if (currentTimeFrame > global.dailyFilePeriods[0][0]) {
await writeMarketStatusReport(currentTimeFrameLabel)
} else {
await writeDailyStatusReport(bot.tradingProcessDate, currentTimeFrameLabel)
await writeDailyStatusReport(currentTimeFrameLabel)
}
async function writeDataRanges(currentTimeFrameLabel) {
for (let outputDatasetIndex = 0; outputDatasetIndex < bot.processNode.referenceParent.processOutput.outputDatasets.length; outputDatasetIndex++) {
async function writeDataRanges() {
for (
let outputDatasetIndex = 0;
outputDatasetIndex < bot.processNode.referenceParent.processOutput.outputDatasets.length;
outputDatasetIndex++
) {
let productCodeName = bot.processNode.referenceParent.processOutput.outputDatasets[outputDatasetIndex].referenceParent.parentNode.config.codeName;
await writeDataRange(contextVariables.dateBeginOfMarket, bot.tradingProcessDate, productCodeName, currentTimeFrameLabel);
await writeDataRange(productCodeName);
}
async function writeDataRange(pBegin, pEnd, productCodeName, currentTimeFrameLabel) {
async function writeDataRange(productCodeName) {
let dataRange = {
begin: pBegin.valueOf(),
end: pEnd.valueOf() + global.ONE_DAY_IN_MILISECONDS
begin: contextVariables.dateBeginOfMarket.valueOf(),
end: tradingProcessDate.valueOf() + global.ONE_DAY_IN_MILISECONDS
}
let fileContent = JSON.stringify(dataRange);
@@ -619,12 +594,16 @@
async function writeTimeFramesFiles(currentTimeFrame, currentTimeFrameLabel) {
for (let outputDatasetIndex = 0; outputDatasetIndex < bot.processNode.referenceParent.processOutput.outputDatasets.length; outputDatasetIndex++) {
for (
let outputDatasetIndex = 0;
outputDatasetIndex < bot.processNode.referenceParent.processOutput.outputDatasets.length;
outputDatasetIndex++
) {
let productCodeName = bot.processNode.referenceParent.processOutput.outputDatasets[outputDatasetIndex].referenceParent.parentNode.config.codeName;
await writeTimeFramesFile(currentTimeFrame, currentTimeFrameLabel, productCodeName, 'Multi-Period-Daily')
await writeTimeFramesFile(currentTimeFrame, currentTimeFrameLabel, productCodeName, 'Multi-Period-Market')
await writeTimeFramesFile( currentTimeFrameLabel, productCodeName, 'Multi-Period-Daily')
await writeTimeFramesFile( currentTimeFrameLabel, productCodeName, 'Multi-Period-Market')
async function writeTimeFramesFile(currentTimeFrame, currentTimeFrameLabel, productCodeName, processType) {
async function writeTimeFramesFile(currentTimeFrameLabel, productCodeName, processType) {
let timeFramesArray = []
timeFramesArray.push(currentTimeFrameLabel)
@@ -642,12 +621,12 @@
}
}
async function writeDailyStatusReport(lastFileDate, currentTimeFrameLabel) {
async function writeDailyStatusReport( currentTimeFrameLabel) {
let reportKey = bot.dataMine + "-" + bot.codeName + "-" + bot.processNode.referenceParent.config.codeName
let thisReport = statusDependencies.statusReports.get(reportKey)
thisReport.file.lastExecution = bot.currentDaytime
thisReport.file.lastFile = lastFileDate
thisReport.file.lastFile = tradingProcessDate
thisReport.file.simulationState = bot.simulationState
thisReport.file.timeFrames = currentTimeFrameLabel
await thisReport.asyncSave()
@@ -661,33 +640,54 @@
thisReport.file.simulationState = bot.simulationState
thisReport.file.timeFrames = currentTimeFrameLabel
logger.newInternalLoop(bot.codeName, bot.process, bot.tradingProcessDate)
logger.newInternalLoop(bot.codeName, bot.process, tradingProcessDate)
await thisReport.asyncSave()
}
}
function checkIfSessionMustStop() {
/*
The natural way for the session to stop is when we reached the
user defined end datetime.
*/
const now = new Date()
if (now.valueOf() >= bot.SESSION.parameters.timeRange.config.finalDatetime) {
const logText = "User Defined End Datetime reached @ " + now.getUTCFullYear() + "/" + (now.getUTCMonth() + 1) + "/" + now.getUTCDate() + ".";
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeProcessFiles -> onMarketStatusReport -> " + logText); }
bot.SESSION.stop('because it just finished.')
return
}
if (bot.SESSION.type === 'Backtesting Session') {
bot.SESSION.stop('Backtesting Session over Market Files Finished.')
return
/*
Backtests needs only one execution of this process to complete.
*/
bot.SESSION.stop('Backtesting Session Finished.')
} else {
/*
The natural way for the session to stop is when we reached the
user defined end datetime.
*/
const now = new Date()
if (now.valueOf() >= bot.SESSION.parameters.timeRange.config.finalDatetime) {
const logText = "User Defined End Datetime reached @ " + now.getUTCFullYear() + "/" + (now.getUTCMonth() + 1) + "/" + now.getUTCDate() + ".";
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeProcessFiles -> onMarketStatusReport -> " + logText); }
bot.SESSION.stop('Final Datetime Reached.')
}
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
/* An unhandled exception occured. in this case we return Fail and log the stack. */
if (err.stack) {
logger.write(MODULE_NAME, "[ERROR] start -> Unhandled Exception. Will Abort this process. err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return
}
/* Some expected file was not found. We will return a RETRY code and move on. */
if ((err.result === "Fail Because" && err.message === "File does not exist.") || err.code === 'The specified key does not exist.') {
logger.write(MODULE_NAME, "[ERROR] File not Found. Will Retry the Process Loop.")
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
return
}
/* Some other handled exception occured. We return Fail and move on. */
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] start -> Handled Exception. Will Abort this process. err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return
}
}
}
@@ -31,7 +31,7 @@ exports.newTradingRecords = function newTradingRecords(bot, logger) {
outputDatasetsMap = undefined
}
function appendRecords(cycle) {
function appendRecords() {
/*
Here we add records to the output files. At the product config property nodePath
we have a pointer to the node that have the information we need to extract.
@@ -57,13 +57,13 @@ exports.newTradingRecords = function newTradingRecords(bot, logger) {
There are a few products configured to be saved only at an specific cycle.
*/
if (product.config.saveAtCycle !== undefined) {
if (cycle !== product.config.saveAtCycle) {
if (tradingEngine.current.episode.cycle.value !== product.config.saveAtCycle) {
return
}
}
/* Clean the file from information of previous executions */
pruneOutputFile(product, outputDatasetArray, tradingEngine.current.episode.candle.end.value)
//pruneOutputFile(product, outputDatasetArray, tradingEngine.current.episode.candle.end.value)
/* Clean Open Records */
if (product.config.saveAsObjects === true) {
@@ -72,6 +72,7 @@ exports.newTradingRecords = function newTradingRecords(bot, logger) {
if (recordProperty.config.codeName === product.config.propertyNameThatDefinesObject) {
/* Remove Open Records */
spliceOpenRecords(j, product, outputDatasetArray)
break
}
}
}
@@ -1,4 +1,4 @@
exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILITIES) {
exports.newTradingSimulation = function newTradingSimulation(bot, logger, tradingEngineModule, UTILITIES) {
/*
This Module represents the trading simulacion. Escentially a loop through a set of candles and
the execution at each loop cycle of the Trading System Protocol.
@@ -23,7 +23,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
chart,
outputDatasetsMap,
writeFiles,
) {
) {
try {
let tradingSystem = bot.simulationState.tradingSystem
@@ -34,10 +34,6 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> finalDatetime = ' + sessionParameters.timeRange.config.finalDatetime) }
/* These are the Modules we will need to run the Simulation */
const TRADING_ENGINE_MODULE = require('./TradingEngine.js')
let tradingEngineModule = TRADING_ENGINE_MODULE.newTradingEngine(bot, logger)
tradingEngineModule.initialize()
const TRADING_RECORDS_MODULE = require('./TradingRecords.js')
let tradingRecordsModule = TRADING_RECORDS_MODULE.newTradingRecords(bot, logger)
tradingRecordsModule.initialize(outputDatasetsMap)
@@ -58,55 +54,59 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
let heartBeatDate
let previousHeartBeatDate
let firstLoopExecution = true
/*
Loop Initialization
Estimation of the Initial Candle to Process in this Run.
*/
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)
throw(global.DEFAULT_FAIL_RESPONSE)
return
}
} else {
let initialCandle
if (bot.FIRST_EXECUTION === true && bot.RESUME === false) {
/* 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) {
initialCandle = Math.trunc(amount)
if (initialCandle < 0) { initialCandle = 0 }
if (initialCandle > 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.
*/
bot.SESSION.stop('Data is not up-to-date enough. Please start the Masters Data Mining Operation.')
return
bot.SESSION.stop('Data is not up-to-date enough. Please start the Masters Data Mining Operation.')
return
}
}
} else {
/*
In this case we already have at the last candle index the next candle to be
processed. We will just continue with this candle.
*/
initialCandle = tradingEngine.current.episode.candle.index.value
}
/*
Main Simulation Loop
*/
let breakLoop = false
for( let i = tradingEngine.current.episode.candle.index.value; i < candles.length; i++) {
console.log('initialCandle = ' + initialCandle)
/* We are going to use this to exit the loop if needed. */
let breakLoop = false
/*
We will assume that we are at the head of the market here. We do this
because the loop could be empty and no validation is going to run. If the
loop is not empty, then the lascCandle() check will override this value
depending on if we really are at the head of the market or not.
*/
tradingEngine.current.episode.headOfTheMarket.value = true
/*
This is the main simulation loop. It will go through the initial candle
until one less than the last candle available. We will never process the last
candle available since it is not considered a closed candle, but a candle
that still can change. So effectively will be processing all closed candles.
*/
for (let i = initialCandle; i < candles.length - 1; i++) {
tradingEngine.current.episode.candle.index.value = i
console.log('index = ' + tradingEngine.current.episode.candle.index.value)
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.
@@ -114,7 +114,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
if (FULL_LOG === true) { logger.write(MODULE_NAME, '[INFO] runSimulation -> loop -> Candle End @ ' + (new Date(candle.end)).toLocaleString()) }
tradingEngineModule.setCurrentCandle(candle) // We move the current candle we are standing at, to the trading engine data structure to make it available to anyone, including conditions and formulas.
/* We emit a heart beat so that the UI can now where we are at the overal process.*/
heartBeat()
@@ -124,6 +124,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
}
if (checkInitialDatetime() === false) {
console.log(' Esta candle esta dentras del Initial Datetime')
continue
}
@@ -134,85 +135,96 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
/*
Do the stuff needed previous to the run like
Episode Counters and Statistics update
Episode Counters and Statistics update. Mantaince is done
once per simulation candle.
*/
tradingSystemModule.mantain()
tradingEpisodeModule.mantain()
tradingEngineModule.mantain()
/* Reset Data Structures */
tradingSystemModule.reset()
tradingEpisodeModule.reset()
tradingEngineModule.reset()
/*
Run the first cycle of the Trading System. In this first cycle we
give some room so that orders can be canceled or filled and we can
write those records into the output memory.
write those records into the output memory. During this cycle new
orders can not be created, since otherwise the could be cancelled at
the second cycle without spending real time at the order book.
*/
tradingEngineModule.setCurrentCycle('First')
await tradingSystemModule.run()
await runCycle()
/* Add new records to the process output */
tradingRecordsModule.appendRecords('First')
/* Reset Data Structures */
tradingSystemModule.reset()
tradingEpisodeModule.reset()
tradingEngineModule.reset()
tradingRecordsModule.appendRecords()
if (breakLoop === true) { break }
/*
Run the second cycle of the Trading System. During this second run
some new orders might be created at slots freed up during the first
run. This allows for example for an Limit Order to be cancelled during the
run. This allows for example for a Limit Order to be cancelled during the
first run, and the same Limit Order definition to spawn a new order
without the need to wait until the next candle.
without the need to wait until the next candle. Orders can not be cancelled
during the second cycle.
*/
tradingEngineModule.setCurrentCycle('Second')
await tradingSystemModule.run()
await runCycle()
/* 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')
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')
breakLoop = true
}
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
}
/*
We check if we need to stop before appending the records so that the stop
reason is also propery recorded.
*/
checkIfWeNeedToStop()
/* Add new records to the process output */
tradingRecordsModule.appendRecords('Second')
tradingRecordsModule.appendRecords()
if (breakLoop === true) {break}
if (breakLoop === true) { break }
async function runCycle() {
console.log(new Date(), 'Function runCycle', ' Cycle = ' + tradingEngine.current.episode.cycle.value)
/* Reset Data Structures */
tradingSystemModule.reset()
tradingEpisodeModule.reset()
tradingEngineModule.reset()
await tradingSystemModule.run()
}
function checkIfWeNeedToStop() {
/* 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.') }
updateEpisode('Session Stopped')
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.') }
updateEpisode('Task Stopped')
breakLoop = true
}
if (checkFinalDatetime() === false) {
closeEpisode('Final Datetime Reached')
breakLoop = true
}
if (checkNextCandle() === false) {
updateEpisode('All Available Candles Processed')
breakLoop = true
}
if (checkMinimunAndMaximunBalance() === false) {
closeEpisode('Min or Max Balance Reached')
breakLoop = true
}
}
}
tradingEngineModule.finalize()
tradingSystemModule.finalize()
tradingRecordsModule.finalize()
tradingEpisodeModule.finalize()
tradingEngineModule = undefined
tradingSystemModule = undefined
tradingRecordsModule = undefined
tradingEpisodeModule = undefined
@@ -347,34 +359,61 @@ 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)
throw(global.DEFAULT_FAIL_RESPONSE)
throw (global.DEFAULT_FAIL_RESPONSE)
}
}
function checkLastCandle() {
function checkNextCandle() {
/*
We skip the candle at the head of the market because it has not closed yet. The procedure to determine if we are at the head of the market is different
when we are processing Market Files than when we are processing Daily Files. TODO Check that the procedure is good for Beta 6
We need to check that the candle we have just processed it is not the last candle.
The candle at the head of the market is already skipped from the loop because it has not closed yet.
Note: for Daily Files, this means that the last candle of each day will never be processed.
*/
if (bot.processingDailyFiles) { // We are processing Daily Files
if (tradingEngine.current.episode.candle.index.value === candles.length - 1) {
/*
When processing daily files, we need a mechanism to turn from one day to the next one.
That mechanism is the one implemented here. If we detect that the next candle is the last candle of
the day, we will advance current process day one day. By doing so, during the next execution, the
simulation will receive the candles and indicators files of the next day.
The first +1 is because array indexes are based on 0.
The second +1 is because we need to compare the next candle (remember that the loops allways avoid the
last candle of the dataset available.)
*/
let candlesPerDay = global.ONE_DAY_IN_MILISECONDS / sessionParameters.timeFrame.config.value
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
/*
Note here that in the last candle of the first day or the second day it will use an incomplete candle and partially calculated indicators.
if we skip these two periods, then there will be a hole in the file since the last period will be missing.
*/
}
}
} else { // We are processing Market Files
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.') }
if (
bot.processingDailyFiles &&
tradingEngine.current.episode.candle.index.value + 1 + 1 === candlesPerDay
) {
/*
Here we found that the next candle of the dataset is the last candle of the day.
It is time to move to the next day so as to receive at the next execution, the indicator files from
the next day. At the same time we will reset the index to be pointing to
the first candle of the new dataset we shall receive. The first candle of the next day starts
at index 0, so we will position the index now at zero.
*/
tradingEngine.current.episode.candle.index.value = 0
tradingEngine.current.episode.processDate.value =
tradingEngine.current.episode.processDate.value + global.ONE_DAY_IN_MILISECONDS
return false
}
/*
We reached the head of the market but we are not at the last candle of a day during
Daily Files processing. We will advance to the next candle index anyways because in the
next execution it will likely have more candles at the dataset. And if it does not,
it will just wait there until it does.
*/
tradingEngine.current.episode.headOfTheMarket.value = true
tradingEngine.current.episode.candle.index.value++
return false
} else {
/* Wd did not reach the head of the market */
tradingEngine.current.episode.headOfTheMarket.value = false
tradingEngine.current.episode.candle.index.value++
return true
}
return true
}
function checkInitialDatetime() {
@@ -448,7 +487,7 @@ exports.newTradingSimulation = function newTradingSimulation(bot, logger, UTILIT
}
} catch (err) {
logger.write(MODULE_NAME, '[ERROR] runSimulation -> err = ' + err.stack)
throw(global.DEFAULT_FAIL_RESPONSE)
throw (global.DEFAULT_FAIL_RESPONSE)
}
}
}
+6 -6
View File
@@ -67,6 +67,7 @@
setUpAppSchema()
setUpSessionFolderName()
/* We validate all parameters received and complete some that might be missing if needed. */
if (checkParemeters() === false) { return }
socialBotsModule.initialize()
@@ -208,6 +209,11 @@
}
function useDefaultDatetimes(initialDefault, finalDefault) {
/*
Note that inside the system, we are going to deal with these
dates in their numeric value representation.
*/
/* Initial Datetime */
if (bot.SESSION.parameters.timeRange.config.initialDatetime === undefined) {
bot.SESSION.parameters.timeRange.config.initialDatetime = initialDefault
@@ -310,7 +316,6 @@
}
function startBackTesting(message) {
bot.tradingProcessDate = new Date(bot.SESSION.parameters.timeRange.config.initialDatetime.valueOf()) // Here we initialize the date of the process.
return true
}
@@ -319,8 +324,6 @@
if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, "[ERROR] initialize -> startLiveTrading -> Key 'codeName' or 'secret' not provided. Plese check that and try again."); }
return false
}
bot.tradingProcessDate = new Date(bot.SESSION.parameters.timeRange.config.initialDatetime.valueOf())
pProcessConfig.liveWaitTime = bot.SESSION.parameters.timeFrame.config.value
return true
}
@@ -332,8 +335,6 @@
return false
}
bot.tradingProcessDate = new Date(bot.SESSION.parameters.timeRange.config.initialDatetime.valueOf())
/* Reduce the balance */
let balancePercentage = 1 // This is the default value
@@ -356,7 +357,6 @@
}
function startPaperTrading(message) {
bot.tradingProcessDate = new Date(bot.SESSION.parameters.timeRange.config.initialDatetime.valueOf())
pProcessConfig.normalWaitTime = bot.SESSION.parameters.timeFrame.config.value
return true
}
+2 -49
View File
@@ -3,9 +3,6 @@
const MODULE_NAME = "Trading Bot";
const FULL_LOG = true;
let USER_BOT_MODULE;
let USER_BOT_COMMONS;
const TRADING_PROCESS_MODULE = require(global.ROOT_DIR + '/LowFrequencyTrading/TradingProcess.js');
const FILE_STORAGE = require('./FileStorage.js');
const SESSION = require(global.ROOT_DIR + 'Session');
@@ -33,53 +30,9 @@
processConfig = pProcessConfig;
if (bot.definedByUI === true) {
/* The code of the bot is defined at the UI. No need to load a file with the code. */
session.initialize(processConfig, onSessionInitialized)
function onSessionInitialized(err) {
callBackFunction(err);
}
return
session.initialize(processConfig, callBackFunction)
}
let filePath = bot.dataMine + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.codeName
filePath += "/User.Bot.js"
fileStorage.getTextFile(filePath, onBotDownloaded);
function onBotDownloaded(err, text) {
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> err = " + err.message);
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> filePath = " + filePath);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return;
}
USER_BOT_MODULE = {}
USER_BOT_MODULE.newUserBot = eval(text); // Use this for production
filePath = bot.dataMine + "/" + "bots" + "/" + bot.repo;
filePath += "/Commons.js"
fileStorage.getTextFile(filePath, onCommonsDownloaded);
function onCommonsDownloaded(err, text) {
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
parentLogger.write(MODULE_NAME, "[WARN] initialize -> onBotDownloaded -> onCommonsDownloaded -> Commons not found: " + err.code || err.message);
callBackFunction(global.DEFAULT_OK_RESPONSE);
return;
}
USER_BOT_COMMONS = {}
USER_BOT_COMMONS.newCommons = eval(text); // Use this for production
session.initialize(onSessionInitialized)
function onSessionInitialized(err) {
callBackFunction(err);
}
}
}
} catch (err) {
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
@@ -337,7 +290,7 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeDataDependencies -> onInizialized -> Execution finished well."); }
switch (processConfig.framework.name) {
case 'Low-Frequency-Trading-Process': {
processFramework = TRADING_PROCESS_MODULE.newTradingProcess(bot, logger, UTILITIES, USER_BOT_MODULE, USER_BOT_COMMONS);
processFramework = TRADING_PROCESS_MODULE.newTradingProcess(bot, logger, UTILITIES);
intitializeProcessFramework();
break;
}
+6
View File
@@ -45,6 +45,12 @@ global.PRECISE = function (floatNumber, precision) {
return this.parseFloat(floatNumber.toFixed(precision))
}
global.REMOVE_TIME = function (datetime) {
const GMT_SECONDS = ':00.000 GMT+0000';
let date = new Date(datetime)
return new Date(date.getUTCFullYear() + "-" + (date.getUTCMonth() + 1) + "-" + date.getUTCDate() + " " + "00:00" + GMT_SECONDS);
}
process.on('uncaughtException', function (err) {
console.log('[ERROR] Task Server -> server -> uncaughtException -> err.message = ' + err.message)
console.log('[ERROR] Task Server -> server -> uncaughtException -> err.stack = ' + err.stack)