Files
Superalgos/Multi-Period-Daily/User.Bot.js
T

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);
}
}
};