1207 lines
64 KiB
JavaScript
1207 lines
64 KiB
JavaScript
exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, BLOB_STORAGE, FILE_STORAGE) {
|
|
|
|
const FULL_LOG = true;
|
|
const INTENSIVE_LOG = false;
|
|
const LOG_FILE_CONTENT = false;
|
|
|
|
const GMT_SECONDS = ':00.000 GMT+0000';
|
|
const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000;
|
|
|
|
const MODULE_NAME = "User Bot";
|
|
|
|
const EXCHANGE_NAME = "Poloniex";
|
|
|
|
const TRADES_FOLDER_NAME = "Trades";
|
|
|
|
const CANDLES_FOLDER_NAME = "Bands";
|
|
const SIMULATED_TRADES_FOLDER_NAME = "Trading-Simulation";
|
|
|
|
const commons = COMMONS.newCommons(bot, logger, UTILITIES);
|
|
|
|
thisObject = {
|
|
initialize: initialize,
|
|
start: start
|
|
};
|
|
|
|
let chrisStorage = BLOB_STORAGE.newBlobStorage(bot, logger);
|
|
let jasonStorage = BLOB_STORAGE.newBlobStorage(bot, logger);
|
|
|
|
let utilities = UTILITIES.newCloudUtilities(bot, logger);
|
|
|
|
let statusDependencies;
|
|
|
|
return thisObject;
|
|
|
|
function initialize(pStatusDependencies, pMonth, pYear, callBackFunction) {
|
|
|
|
try {
|
|
|
|
logger.fileName = MODULE_NAME;
|
|
logger.initialize();
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); }
|
|
|
|
statusDependencies = pStatusDependencies;
|
|
|
|
commons.initializeStorage(chrisStorage, jasonStorage, onInizialized);
|
|
|
|
function onInizialized(err) {
|
|
|
|
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> onInizialized -> Initialization Succeed."); }
|
|
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
|
|
|
} else {
|
|
logger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> err = " + err.message);
|
|
callBackFunction(err);
|
|
}
|
|
}
|
|
|
|
} catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
|
|
function start(callBackFunction) {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); }
|
|
|
|
let market = global.MARKET;
|
|
|
|
/* Context Variables */
|
|
|
|
let contextVariables = {
|
|
lastTradeFile: undefined, // Datetime of the last file files sucessfully produced by this process.
|
|
firstTradeFile: undefined, // Datetime of the first trade file in the whole market history.
|
|
maxTradeFile: 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.
|
|
let processDate; // Holds the processing date.
|
|
|
|
getContextVariables();
|
|
|
|
function getContextVariables() {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Entering function."); }
|
|
|
|
let thisReport;
|
|
let reportKey;
|
|
let statusReport;
|
|
|
|
/* We look first for Charly in order to get when the market starts. */
|
|
|
|
reportKey = "AAMasters" + "-" + "AACharly" + "-" + "Poloniex-Historic-Trades" + "-" + "dataSet.V1";
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
|
|
|
|
statusReport = statusDependencies.statusReports.get(reportKey);
|
|
|
|
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
|
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
|
|
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
|
return;
|
|
}
|
|
|
|
if (statusReport.status === "Status Report is corrupt.") {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
|
|
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
|
return;
|
|
}
|
|
|
|
thisReport = statusDependencies.statusReports.get(reportKey).file;
|
|
|
|
if (thisReport.lastFile === undefined) {
|
|
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey);
|
|
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> It is too early too run this process since the trade history of the market is not there yet.");
|
|
|
|
let customOK = {
|
|
result: global.CUSTOM_OK_RESPONSE.result,
|
|
message: "Dependency does not exist."
|
|
}
|
|
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message);
|
|
callBackFunction(customOK);
|
|
return;
|
|
}
|
|
|
|
contextVariables.firstTradeFile = new Date(thisReport.lastFile.year + "-" + thisReport.lastFile.month + "-" + thisReport.lastFile.days + " " + thisReport.lastFile.hours + ":" + thisReport.lastFile.minutes + GMT_SECONDS);
|
|
|
|
/* Second, we get the report from Chris, to know when the marted ends. */
|
|
|
|
reportKey = "AAMasters" + "-" + "AAChris" + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1";
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
|
|
|
|
statusReport = statusDependencies.statusReports.get(reportKey);
|
|
|
|
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
|
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
|
|
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
|
return;
|
|
}
|
|
|
|
if (statusReport.status === "Status Report is corrupt.") {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
|
|
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
|
return;
|
|
}
|
|
|
|
thisReport = statusDependencies.statusReports.get(reportKey).file;
|
|
|
|
if (thisReport.lastFile === undefined) {
|
|
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey);
|
|
|
|
let customOK = {
|
|
result: global.CUSTOM_OK_RESPONSE.result,
|
|
message: "Dependency not ready."
|
|
}
|
|
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message);
|
|
callBackFunction(customOK);
|
|
return;
|
|
}
|
|
|
|
contextVariables.maxTradeFile = new Date(thisReport.lastFile.valueOf());
|
|
|
|
/* Finally we get our own Status Report. */
|
|
|
|
reportKey = "AAMasters" + "-" + "AAJason" + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1";
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
|
|
|
|
statusReport = statusDependencies.statusReports.get(reportKey);
|
|
|
|
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
|
|
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
|
|
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
|
return;
|
|
}
|
|
|
|
if (statusReport.status === "Status Report is corrupt.") {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because self dependecy Status Report is corrupt. Aborting Process.");
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
return;
|
|
}
|
|
|
|
thisReport = statusDependencies.statusReports.get(reportKey).file;
|
|
|
|
if (thisReport.lastFile !== undefined) {
|
|
|
|
contextVariables.lastTradeFile = new Date(thisReport.lastFile);
|
|
|
|
/*
|
|
The trades objects needs to be calculated over more than one day in some situations. In order to simplify the calculations we will
|
|
always load the last 2 days of bands, and run the calculations on that array.
|
|
|
|
1. So first we will load the bands file of processDay -1.
|
|
2. Secondly we will load the bands file of processDay.
|
|
|
|
After reading these two files we will add all bands to a unique array.
|
|
*/
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> thisReport.lastFile !== undefined"); }
|
|
|
|
buildTrades();
|
|
return;
|
|
|
|
} else {
|
|
|
|
/*
|
|
In the case when there is no status report, we take the date of the file with the first trades as the begining of the market. Then we will
|
|
go one day further in time, so that the previous day does fine a file at the begining of the market.
|
|
*/
|
|
|
|
contextVariables.lastTradeFile = new Date(contextVariables.firstTradeFile.getUTCFullYear() + "-" + (contextVariables.firstTradeFile.getUTCMonth() + 1) + "-" + contextVariables.firstTradeFile.getUTCDate() + " " + "00:00" + GMT_SECONDS);
|
|
contextVariables.lastTradeFile = new Date(contextVariables.lastTradeFile.valueOf() + ONE_DAY_IN_MILISECONDS);
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> thisReport.lastFile === undefined"); }
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> contextVariables.lastTradeFile = " + contextVariables.lastTradeFile); }
|
|
|
|
buildTrades();
|
|
return;
|
|
}
|
|
|
|
} catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> err = " + err.message);
|
|
if (err.message === "Cannot read property 'file' of undefined") {
|
|
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Check the bot configuration to see if all of its statusDependencies declarations are correct. ");
|
|
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys));
|
|
}
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
|
|
function buildTrades() {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> Entering function."); }
|
|
|
|
let n;
|
|
processDate = new Date(contextVariables.lastTradeFile.valueOf() - ONE_DAY_IN_MILISECONDS); // Go back one day to start well when we advance time at the begining of the loop.
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> processDate = " + processDate); }
|
|
|
|
advanceTime();
|
|
|
|
function advanceTime() {
|
|
|
|
try {
|
|
|
|
logger.newInternalLoop(bot.codeName, bot.process);
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> advanceTime -> Entering function."); }
|
|
|
|
processDate = new Date(processDate.valueOf() + ONE_DAY_IN_MILISECONDS);
|
|
previousDay = new Date(processDate.valueOf() - ONE_DAY_IN_MILISECONDS);
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> advanceTime -> processDate = " + processDate); }
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> advanceTime -> previousDay = " + previousDay); }
|
|
|
|
/* Validation that we are not going past the head of the market. */
|
|
|
|
if (processDate.valueOf() > contextVariables.maxTradeFile.valueOf()) {
|
|
|
|
const logText = "Head of the market found @ " + previousDay.getUTCFullYear() + "/" + (previousDay.getUTCMonth() + 1) + "/" + previousDay.getUTCDate() + ".";
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> advanceTime -> " + logText); }
|
|
|
|
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
|
return;
|
|
|
|
}
|
|
|
|
periodsLoop();
|
|
|
|
} catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> advanceTime -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
|
|
function periodsLoop() {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> periodsLoop -> Entering function."); }
|
|
|
|
/*
|
|
|
|
We will iterate through all posible timePeriods.
|
|
|
|
*/
|
|
|
|
n = 0 // loop Variable representing each possible period as defined at the periods array.
|
|
|
|
loopBody();
|
|
|
|
} catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
|
|
function loopBody() {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> loopBody -> Entering function."); }
|
|
|
|
const timePeriod = global.dailyFilePeriods[n][1];
|
|
|
|
let marketFile;
|
|
|
|
let LRCMap = new Map();
|
|
let percentageBandwidthMap = new Map();
|
|
let bollingerBandsMap = new Map();
|
|
let bollingerChannelsArray = [];
|
|
let bollingerSubChannelsArray = [];
|
|
|
|
let candles = [];
|
|
let recordsArray = [];
|
|
let conditionsArray = [];
|
|
let simulationLogic = {};
|
|
|
|
nextLRC();
|
|
|
|
function nextLRC() {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextLRC -> Entering function."); }
|
|
|
|
let dateForPath = fileDate.getUTCFullYear() + '/' + utilities.pad(fileDate.getUTCMonth() + 1, 2) + '/' + utilities.pad(fileDate.getUTCDate(), 2);
|
|
let fileName = market.assetA + '_' + market.assetB + ".json"
|
|
|
|
let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion;
|
|
let filePath = filePathRoot + "/Output/" + CANDLE_STAIRS_FOLDER_NAME + '/' + "Multi-Period-Daily" + "/" + timePeriod + "/" + dateForPath;
|
|
|
|
|
|
|
|
let fileName = market.assetA + '_' + market.assetB + ".json";
|
|
|
|
let filePathRoot = "AAVikings" + "/" + "AAGauss" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion;
|
|
let filePath = filePathRoot + "/Output/" + LRC_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod;
|
|
|
|
gaussStorage.getTextFile(filePath, fileName, onFileReceived, true);
|
|
|
|
function onFileReceived(err, text) {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> Entering function."); }
|
|
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> text = " + text); }
|
|
|
|
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
|
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> err = " + err.message);
|
|
callBackFunction(err);
|
|
return;
|
|
|
|
}
|
|
|
|
marketFile = JSON.parse(text);
|
|
|
|
buildLRC();
|
|
|
|
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextLRC -> onFileReceived -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextLRC -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
|
|
function buildLRC() {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildLRC -> Entering function."); }
|
|
|
|
try {
|
|
|
|
let previous;
|
|
|
|
for (let i = 0; i < marketFile.length; i++) {
|
|
|
|
let LRC = {
|
|
begin: marketFile[i][0],
|
|
end: marketFile[i][1],
|
|
_15: marketFile[i][2],
|
|
_30: marketFile[i][3],
|
|
_60: marketFile[i][4]
|
|
};
|
|
|
|
if (previous !== undefined) {
|
|
|
|
if (previous._15 > LRC._15) { LRC.direction15 = 'down'; }
|
|
if (previous._15 < LRC._15) { LRC.direction15 = 'up'; }
|
|
if (previous._15 === LRC._15) { LRC.direction15 = 'side'; }
|
|
|
|
if (previous._30 > LRC._30) { LRC.direction30 = 'down'; }
|
|
if (previous._30 < LRC._30) { LRC.direction30 = 'up'; }
|
|
if (previous._30 === LRC._30) { LRC.direction30 = 'side'; }
|
|
|
|
if (previous._60 > LRC._60) { LRC.direction60 = 'down'; }
|
|
if (previous._60 < LRC._60) { LRC.direction60 = 'up'; }
|
|
if (previous._60 === LRC._60) { LRC.direction60 = 'side'; }
|
|
|
|
}
|
|
|
|
LRC.previous = previous;
|
|
|
|
LRCMap.set(LRC.begin, LRC);
|
|
|
|
previous = LRC;
|
|
}
|
|
|
|
nextPercentageBandwidth();
|
|
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildLRC -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
|
|
function nextPercentageBandwidth() {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> Entering function."); }
|
|
|
|
let fileName = market.assetA + '_' + market.assetB + ".json";
|
|
|
|
let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion;
|
|
let filePath = filePathRoot + "/Output/" + PERCENTAGE_BANDWIDTH_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod;
|
|
|
|
chrisStorage.getTextFile(filePath, fileName, onFileReceived, true);
|
|
|
|
function onFileReceived(err, text) {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> Entering function."); }
|
|
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> text = " + text); }
|
|
|
|
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
|
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> err = " + err.message);
|
|
callBackFunction(err);
|
|
return;
|
|
|
|
}
|
|
|
|
marketFile = JSON.parse(text);
|
|
|
|
buildPercentageBandwidthMap();
|
|
|
|
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> onFileReceived -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextPercentageBandwidth -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
|
|
function buildPercentageBandwidthMap() {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildPercentageBandwidthMap -> Entering function."); }
|
|
|
|
try {
|
|
|
|
let previous;
|
|
|
|
for (let i = 0; i < marketFile.length; i++) {
|
|
|
|
let percentageBandwidth = {
|
|
begin: marketFile[i][0],
|
|
end: marketFile[i][1],
|
|
value: marketFile[i][2],
|
|
movingAverage: marketFile[i][3],
|
|
bandwidth: marketFile[i][4]
|
|
};
|
|
|
|
if (previous !== undefined) {
|
|
|
|
if (previous.movingAverage > percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'down'; }
|
|
if (previous.movingAverage < percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'up'; }
|
|
if (previous.movingAverage === percentageBandwidth.movingAverage) { percentageBandwidth.direction = 'side'; }
|
|
|
|
}
|
|
|
|
percentageBandwidth.previous = previous;
|
|
|
|
percentageBandwidthMap.set(percentageBandwidth.begin, percentageBandwidth);
|
|
|
|
previous = percentageBandwidth;
|
|
}
|
|
|
|
nextBollingerBands();
|
|
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildPercentageBandwidthMap -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
|
|
function nextBollingerBands() {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerBands -> Entering function."); }
|
|
|
|
let fileName = market.assetA + '_' + market.assetB + ".json";
|
|
|
|
let filePathRoot = bot.devTeam + "/" + "AAChris" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion;
|
|
let filePath = filePathRoot + "/Output/" + BOLLINGER_BANDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod;
|
|
|
|
chrisStorage.getTextFile(filePath, fileName, onFileReceived, true);
|
|
|
|
function onFileReceived(err, text) {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> Entering function."); }
|
|
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> text = " + text); }
|
|
|
|
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
|
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> err = " + err.message);
|
|
callBackFunction(err);
|
|
return;
|
|
|
|
}
|
|
|
|
marketFile = JSON.parse(text);
|
|
|
|
buildBollingerBandsMap();
|
|
|
|
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerBands -> onFileReceived -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerBands -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
|
|
function buildBollingerBandsMap() {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildBollingerBandsMap -> Entering function."); }
|
|
|
|
try {
|
|
|
|
let previous;
|
|
|
|
for (let i = 0; i < marketFile.length; i++) {
|
|
|
|
let bollingerBand = {
|
|
begin: marketFile[i][0],
|
|
end: marketFile[i][1],
|
|
movingAverage: marketFile[i][2],
|
|
standardDeviation: marketFile[i][3],
|
|
deviation: marketFile[i][4]
|
|
};
|
|
|
|
if (previous !== undefined) {
|
|
|
|
if (previous.movingAverage > bollingerBand.movingAverage) { bollingerBand.direction = 'down'; }
|
|
if (previous.movingAverage < bollingerBand.movingAverage) { bollingerBand.direction = 'up'; }
|
|
if (previous.movingAverage === bollingerBand.movingAverage) { bollingerBand.direction = 'side'; }
|
|
|
|
}
|
|
|
|
bollingerBand.previous = previous;
|
|
|
|
bollingerBandsMap.set(bollingerBand.begin, bollingerBand);
|
|
|
|
previous = bollingerBand;
|
|
}
|
|
|
|
nextBollingerChannels();
|
|
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildBollingerBandsMap -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
|
|
function nextBollingerChannels() {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerChannels -> Entering function."); }
|
|
|
|
let fileName = market.assetA + '_' + market.assetB + ".json";
|
|
|
|
let filePathRoot = bot.devTeam + "/" + "AAPaula" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion;
|
|
let filePath = filePathRoot + "/Output/" + BOLLINGER_CHANNELS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod;
|
|
|
|
chrisStorage.getTextFile(filePath, fileName, onFileReceived, true);
|
|
|
|
function onFileReceived(err, text) {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> Entering function."); }
|
|
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> text = " + text); }
|
|
|
|
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
|
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> err = " + err.message);
|
|
callBackFunction(err);
|
|
return;
|
|
|
|
}
|
|
|
|
marketFile = JSON.parse(text);
|
|
|
|
buildBollingerChannelsArray();
|
|
|
|
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerChannels -> onFileReceived -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerChannels -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
|
|
function buildBollingerChannelsArray() {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildBollingerChannelsArray -> Entering function."); }
|
|
|
|
try {
|
|
|
|
let previous;
|
|
|
|
for (let i = 0; i < marketFile.length; i++) {
|
|
|
|
let bollingerChannel = {
|
|
begin: marketFile[i][0],
|
|
end: marketFile[i][1],
|
|
direction: marketFile[i][2],
|
|
period: marketFile[i][3],
|
|
firstMovingAverage: marketFile[i][4],
|
|
lastMovingAverage: marketFile[i][5],
|
|
firstDeviation: marketFile[i][6],
|
|
lastDeviation: marketFile[i][7]
|
|
};
|
|
|
|
bollingerChannel.previous = previous;
|
|
|
|
bollingerChannelsArray.push(bollingerChannel);
|
|
|
|
previous = bollingerChannel;
|
|
}
|
|
|
|
nextBollingerSubChannels();
|
|
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildBollingerChannelsArray -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
|
|
function nextBollingerSubChannels() {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> Entering function."); }
|
|
|
|
let fileName = market.assetA + '_' + market.assetB + ".json";
|
|
|
|
let filePathRoot = bot.devTeam + "/" + "AAPaula" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion;
|
|
let filePath = filePathRoot + "/Output/" + BOLLINGER_SUB_CHANNELS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod;
|
|
|
|
chrisStorage.getTextFile(filePath, fileName, onFileReceived, true);
|
|
|
|
function onFileReceived(err, text) {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> Entering function."); }
|
|
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> text = " + text); }
|
|
|
|
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
|
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> err = " + err.message);
|
|
callBackFunction(err);
|
|
return;
|
|
|
|
}
|
|
|
|
marketFile = JSON.parse(text);
|
|
|
|
buildBollingerSubChannelsArray();
|
|
|
|
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> onFileReceived -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextBollingerSubChannels -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
|
|
function buildBollingerSubChannelsArray() {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildBollingerSubChannelsArray -> Entering function."); }
|
|
|
|
try {
|
|
|
|
let previous;
|
|
|
|
for (let i = 0; i < marketFile.length; i++) {
|
|
|
|
let bollingerSubChannel = {
|
|
begin: marketFile[i][0],
|
|
end: marketFile[i][1],
|
|
direction: marketFile[i][2],
|
|
slope: marketFile[i][3],
|
|
period: marketFile[i][4],
|
|
firstMovingAverage: marketFile[i][5],
|
|
lastMovingAverage: marketFile[i][6],
|
|
firstDeviation: marketFile[i][7],
|
|
lastDeviation: marketFile[i][8]
|
|
};
|
|
|
|
bollingerSubChannel.previous = previous;
|
|
|
|
bollingerSubChannelsArray.push(bollingerSubChannel);
|
|
|
|
previous = bollingerSubChannel;
|
|
}
|
|
|
|
nextCandlesFile();
|
|
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildBollingerSubChannelsArray -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
|
|
function nextCandlesFile() {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextCandlesFile -> Entering function."); }
|
|
|
|
let fileName = market.assetA + '_' + market.assetB + ".json";
|
|
|
|
let filePathRoot = bot.devTeam + "/" + "AAOlivia" + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion;
|
|
let filePath = filePathRoot + "/Output/" + CANDLES_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod;
|
|
|
|
oliviaStorage.getTextFile(filePath, fileName, onFileReceived, true);
|
|
|
|
function onFileReceived(err, text) {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> Entering function."); }
|
|
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> text = " + text); }
|
|
|
|
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
|
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> err = " + err.message);
|
|
callBackFunction(err);
|
|
return;
|
|
|
|
}
|
|
|
|
marketFile = JSON.parse(text);
|
|
|
|
buildCandles();
|
|
|
|
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextCandlesFile -> onFileReceived -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> nextCandlesFile -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
|
|
function buildCandles() {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> buildCandles -> Entering function."); }
|
|
|
|
try {
|
|
|
|
let previous;
|
|
|
|
for (let i = 0; i < marketFile.length; i++) {
|
|
|
|
let candle = {
|
|
open: undefined,
|
|
close: undefined,
|
|
min: 10000000000000,
|
|
max: 0,
|
|
begin: undefined,
|
|
end: undefined,
|
|
direction: undefined
|
|
};
|
|
|
|
candle.min = marketFile[i][0];
|
|
candle.max = marketFile[i][1];
|
|
|
|
candle.open = marketFile[i][2];
|
|
candle.close = marketFile[i][3];
|
|
|
|
candle.begin = marketFile[i][4];
|
|
candle.end = marketFile[i][5];
|
|
|
|
if (candle.open > candle.close) { candle.direction = 'down'; }
|
|
if (candle.open < candle.close) { candle.direction = 'up'; }
|
|
if (candle.open === candle.close) { candle.direction = 'side'; }
|
|
|
|
candle.previous = previous;
|
|
|
|
candles.push(candle);
|
|
|
|
previous = candle;
|
|
}
|
|
|
|
commons.runSimulation(
|
|
candles,
|
|
bollingerBandsMap,
|
|
percentageBandwidthMap,
|
|
LRCMap,
|
|
bollingerChannelsArray,
|
|
bollingerSubChannelsArray,
|
|
recordsArray,
|
|
conditionsArray,
|
|
simulationLogic,
|
|
outputPeriod,
|
|
writeRecordsFile)
|
|
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> buildCandles -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
|
|
function writeRecordsFile() {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeRecordsFile -> Entering function."); }
|
|
|
|
let separator = "";
|
|
let fileRecordCounter = 0;
|
|
|
|
let fileContent = "";
|
|
|
|
for (let i = 0; i < recordsArray.length; i++) {
|
|
|
|
let record = recordsArray[i];
|
|
|
|
fileContent = fileContent + separator + '[' +
|
|
record.begin + "," +
|
|
record.end + "," +
|
|
record.type + "," +
|
|
record.rate + "," +
|
|
record.amount + "," +
|
|
record.balanceA + "," +
|
|
record.balanceB + "," +
|
|
record.profit + "," +
|
|
record.lastProfit + "," +
|
|
record.stopLoss + "," +
|
|
record.roundtrips + "," +
|
|
record.hits + "," +
|
|
record.fails + "," +
|
|
record.hitRatio + "," +
|
|
record.ROI + "," +
|
|
record.periods + "," +
|
|
record.days + "," +
|
|
record.anualizedRateOfReturn + "," +
|
|
record.sellRate + "," +
|
|
record.lastProfitPercent + "," +
|
|
record.strategy + "," +
|
|
record.strategyPhase + "," +
|
|
record.buyOrder + "," +
|
|
record.stopLossPhase + "," +
|
|
record.buyOrderPhase + "]";
|
|
|
|
if (separator === "") { separator = ","; }
|
|
|
|
fileRecordCounter++;
|
|
|
|
}
|
|
|
|
fileContent = "[" + fileContent + "]";
|
|
|
|
let fileName = '' + market.assetA + '_' + market.assetB + '.json';
|
|
|
|
let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion;
|
|
let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod;
|
|
|
|
jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated);
|
|
|
|
function onFileCreated(err) {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> Entering function."); }
|
|
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> fileContent = " + fileContent); }
|
|
|
|
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
|
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> err = " + err.message);
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> filePath = " + filePath);
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB);
|
|
|
|
callBackFunction(err);
|
|
return;
|
|
|
|
}
|
|
|
|
writeConditionsFile();
|
|
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> onFileCreated -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeRecordsFile -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
|
|
function writeConditionsFile() {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeConditionsFile -> Entering function."); }
|
|
|
|
let separator = "";
|
|
let fileRecordCounter = 0;
|
|
|
|
let fileContent = "";
|
|
|
|
for (let i = 0; i < conditionsArray.length; i++) {
|
|
|
|
let record = conditionsArray[i];
|
|
|
|
let conditions = "";
|
|
let conditionsSeparator = "";
|
|
|
|
for (let j = 0; j < record.length - 1; j++) {
|
|
conditions = conditions + conditionsSeparator + record[j];
|
|
if (conditionsSeparator === "") { conditionsSeparator = ","; }
|
|
}
|
|
|
|
conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']'; // The last item contains an Array of condition values.
|
|
|
|
fileContent = fileContent + separator + '[' + conditions + ']';
|
|
|
|
if (separator === "") { separator = ","; }
|
|
|
|
fileRecordCounter++;
|
|
|
|
}
|
|
|
|
fileContent = "[" + fileContent + "]";
|
|
fileContent = "[" + JSON.stringify(simulationLogic) + "," + fileContent + "]";
|
|
let fileName = '' + market.assetA + '_' + market.assetB + '.json';
|
|
|
|
let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.PLATFORM_CONFIG.codeName + "." + global.PLATFORM_CONFIG.version.major + "." + global.PLATFORM_CONFIG.version.minor + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion;
|
|
let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Market" + "/" + timePeriod;
|
|
|
|
jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated);
|
|
|
|
function onFileCreated(err) {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> Entering function."); }
|
|
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> fileContent = " + fileContent); }
|
|
|
|
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
|
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> err = " + err.message);
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> filePath = " + filePath);
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB);
|
|
|
|
callBackFunction(err);
|
|
return;
|
|
|
|
}
|
|
|
|
controlLoop();
|
|
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> onFileCreated -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildRecords -> loopBody -> writeConditionsFile -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> loopBody -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
|
|
function controlLoop() {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> controlLoop -> Entering function."); }
|
|
|
|
n++;
|
|
|
|
if (n < global.dailyFilePeriods.length) {
|
|
|
|
loopBody();
|
|
|
|
} else {
|
|
|
|
n = 0;
|
|
|
|
writeDataRanges(onWritten);
|
|
|
|
function onWritten(err) {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> buildTrades -> controlLoop -> onWritten -> Entering function."); }
|
|
|
|
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> controlLoop -> onWritten -> err = " + err.message);
|
|
callBackFunction(err);
|
|
return;
|
|
}
|
|
|
|
writeStatusReport(processDate, advanceTime);
|
|
|
|
} catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> controlLoop -> onWritten -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
} catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> periodsLoop -> controlLoop -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> buildTrades -> err.message = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
|
|
function writeDataRanges(callBack) {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRanges -> Entering function."); }
|
|
|
|
writeDataRange(contextVariables.firstTradeFile, processDate, SIMULATED_TRADES_FOLDER_NAME, onTradesTradesDataRangeWritten);
|
|
|
|
function onTradesTradesDataRangeWritten(err) {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRanges -> Entering function."); }
|
|
|
|
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
|
logger.write(MODULE_NAME, "[ERROR] writeDataRanges -> writeDataRanges -> onTradesTradesDataRangeWritten -> err = " + err.message);
|
|
callBack(err);
|
|
return;
|
|
}
|
|
|
|
callBack(global.DEFAULT_OK_RESPONSE);
|
|
|
|
}
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> writeDataRanges -> err = " + err.message);
|
|
callBack(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
|
|
}
|
|
|
|
function writeDataRange(pBegin, pEnd, pProductFolder, callBack) {
|
|
|
|
try {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> Entering function."); }
|
|
|
|
let dataRange = {
|
|
begin: pBegin.valueOf(),
|
|
end: pEnd.valueOf()
|
|
};
|
|
|
|
let fileContent = JSON.stringify(dataRange);
|
|
|
|
let fileName = 'Data.Range.' + market.assetA + '_' + market.assetB + '.json';
|
|
let filePath = bot.filePathRoot + "/Output/" + pProductFolder + "/" + bot.process;
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> fileName = " + fileName); }
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> filePath = " + filePath); }
|
|
|
|
jasonStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated);
|
|
|
|
function onFileCreated(err) {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Entering function."); }
|
|
|
|
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> writeDataRange -> onFileCreated -> err = " + err.message);
|
|
callBack(err);
|
|
return;
|
|
}
|
|
|
|
if (LOG_FILE_CONTENT === true) {
|
|
logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Content written = " + fileContent);
|
|
}
|
|
|
|
callBack(global.DEFAULT_OK_RESPONSE);
|
|
}
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> writeDataRange -> err = " + err.message);
|
|
callBack(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
|
|
function writeStatusReport(lastFileDate, callBack) {
|
|
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> Entering function."); }
|
|
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> lastFileDate = " + lastFileDate); }
|
|
|
|
try {
|
|
|
|
let reportKey = "AAMasters" + "-" + "AAJason" + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1";
|
|
let thisReport = statusDependencies.statusReports.get(reportKey);
|
|
|
|
thisReport.file.lastExecution = bot.processDatetime;
|
|
thisReport.file.lastFile = lastFileDate;
|
|
thisReport.save(callBack);
|
|
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
}
|
|
catch (err) {
|
|
logger.write(MODULE_NAME, "[ERROR] start -> err.message = " + err.message);
|
|
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
|
}
|
|
}
|
|
};
|