Files
Superalgos/Datasource.js
T

461 lines
19 KiB
JavaScript

exports.newDatasource = function newDatasource(BOT, DEBUG_MODULE, FILE_STORAGE) {
const FULL_LOG = true;
/*
This module allows trading bots to access information stored at the cloud storage.
*/
const MODULE_NAME = "Datasource";
thisObject = {
initialize: initialize,
candlesFiles: new Map, // Complete sets of candles for different Time Periods. For Time Periods < 1hs sets are of current day only, otherwise whole market.
candlesMap: new Map, // The last 10 candles for each Time Period will be stored here.
stairsFiles: new Map, // Complete sets of patterns for different Time Periods. For Time Periods < 1hs sets are of current day only, otherwise whole market.
stairsMap: new Map // The patterns we are currently in will be stored here.
};
let bot = BOT;
const logger = DEBUG_MODULE.newDebugLog();
logger.fileName = MODULE_NAME;
logger.bot = bot;
let marketFilesPeriods =
'[' +
'[' + 24 * 60 * 60 * 1000 + ',' + '"24-hs"' + ']' + ',' +
'[' + 12 * 60 * 60 * 1000 + ',' + '"12-hs"' + ']' + ',' +
'[' + 8 * 60 * 60 * 1000 + ',' + '"08-hs"' + ']' + ',' +
'[' + 6 * 60 * 60 * 1000 + ',' + '"06-hs"' + ']' + ',' +
'[' + 4 * 60 * 60 * 1000 + ',' + '"04-hs"' + ']' + ',' +
'[' + 3 * 60 * 60 * 1000 + ',' + '"03-hs"' + ']' + ',' +
'[' + 2 * 60 * 60 * 1000 + ',' + '"02-hs"' + ']' + ',' +
'[' + 1 * 60 * 60 * 1000 + ',' + '"01-hs"' + ']' + ']';
marketFilesPeriods = JSON.parse(marketFilesPeriods);
let dailyFilePeriods =
'[' +
'[' + 45 * 60 * 1000 + ',' + '"45-min"' + ']' + ',' +
'[' + 40 * 60 * 1000 + ',' + '"40-min"' + ']' + ',' +
'[' + 30 * 60 * 1000 + ',' + '"30-min"' + ']' + ',' +
'[' + 20 * 60 * 1000 + ',' + '"20-min"' + ']' + ',' +
'[' + 15 * 60 * 1000 + ',' + '"15-min"' + ']' + ',' +
'[' + 10 * 60 * 1000 + ',' + '"10-min"' + ']' + ',' +
'[' + 05 * 60 * 1000 + ',' + '"05-min"' + ']' + ',' +
'[' + 04 * 60 * 1000 + ',' + '"04-min"' + ']' + ',' +
'[' + 03 * 60 * 1000 + ',' + '"03-min"' + ']' + ',' +
'[' + 02 * 60 * 1000 + ',' + '"02-min"' + ']' + ',' +
'[' + 01 * 60 * 1000 + ',' + '"01-min"' + ']' + ']';
dailyFilePeriods = JSON.parse(dailyFilePeriods);
let oliviaAzureFileStorage = FILE_STORAGE.newAzureFileStorage(bot);
let tomAzureFileStorage = FILE_STORAGE.newAzureFileStorage(bot);
return thisObject;
function initialize(callBackFunction) {
try {
if (FULL_LOG === true) { logger.write("[INFO] initialize -> Entering function."); }
initializeOliviaStorage();
function initializeOliviaStorage() {
oliviaAzureFileStorage.initialize("AAOlivia", onInizialized);
function onInizialized(err) {
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
initializeTomStorage();
} else {
logger.write("[ERROR] initialize -> initializeOliviaStorage -> err = " + err.message);
callBackFunction(err);
}
}
}
function initializeTomStorage() {
tomAzureFileStorage.initialize("AATom", onInizialized);
function onInizialized(err) {
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
getCandles(onDone);
} else {
logger.write("[ERROR] initialize -> initializeTomStorage -> err = " + err.message);
callBackFunction(err);
}
}
}
function onDone(err) {
try {
switch (err.result) {
case global.DEFAULT_OK_RESPONSE.result: {
logger.write("[INFO] initialize -> onDone -> Execution finished well. :-)");
callBackFunction(global.DEFAULT_OK_RESPONSE);
return;
}
break;
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
logger.write("[ERROR] initialize -> onDone -> Retry Later. Requesting Execution Retry.");
callBackFunction(err);
return;
}
break;
case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
logger.write("[ERROR] initialize -> onDone -> Operation Failed. Aborting the process.");
callBackFunction(err);
return;
}
break;
}
} catch (err) {
logger.write("[ERROR] initialize -> onDone -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function getCandles(callBack) {
try {
/*
We will read several files with candles for the current day. We will use these files as an input
to make trading decitions later.
*/
getMarketFiles();
function getMarketFiles() {
try {
/* Now we will get the market files */
for (i = 0; i < marketFilesPeriods.length; i++) {
let periodTime = marketFilesPeriods[i][0];
let periodName = marketFilesPeriods[i][1];
getFile(oliviaAzureFileStorage, "@AssetA_@AssetB.json", "@Exchange/Output/Candles/Multi-Period-Market/@Period", periodName, undefined, onFileReceived, callBack);
function onFileReceived(file) {
thisObject.candlesFiles.set(periodName, file);
if (thisObject.candlesFiles.size === marketFilesPeriods.length) {
getDailyFiles();
}
}
}
} catch (err) {
logger.write("[ERROR] getCandles -> getMarketFiles -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
function getDailyFiles() {
try {
for (i = 0; i < dailyFilePeriods.length; i++) {
let periodTime = dailyFilePeriods[i][0];
let periodName = dailyFilePeriods[i][1];
getFile(oliviaAzureFileStorage, "@AssetA_@AssetB.json", "@Exchange/Output/Candles/Multi-Period-Daily/@Period/@Year/@Month/@Day", periodName, processDatetime, onFileReceived, callBack);
function onFileReceived(file) {
thisObject.candlesFiles.set(periodName, file);
if (thisObject.candlesFiles.size === dailyFilePeriods.length + marketFilesPeriods.length) {
getCandlesWeAreIn();
}
}
}
} catch (err) {
logger.write("[ERROR] getCandles -> getDailyFiles -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
function getCandlesWeAreIn() {
try {
let counter = 0;
thisObject.candlesFiles.forEach(getCurrentCandles);
function getCurrentCandles(pCandlesFile, pPeriodName, map) {
let candlesArray = [];
for (i = 0; i < pCandlesFile.length; i++) {
let candle = {
open: undefined,
close: undefined,
min: 10000000000000,
max: 0,
begin: undefined,
end: undefined,
direction: undefined
};
candle.min = pCandlesFile[i][0];
candle.max = pCandlesFile[i][1];
candle.open = pCandlesFile[i][2];
candle.close = pCandlesFile[i][3];
candle.begin = pCandlesFile[i][4];
candle.end = pCandlesFile[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'; }
/* We are going to store the last 10 candles per period, which will give the bot a good sense of where it is. */
let timePeriod = candle.end - candle.begin + 1; // In miliseconds. (remember each candle spans a period minus one milisecond)
if (candle.begin >= processDatetime.valueOf() - timePeriod * 10 && candle.end <= processDatetime.valueOf()) {
candlesArray.push(candle);
}
}
thisObject.candlesMap.set(pPeriodName, candlesArray);
counter++;
if (counter === thisObject.candlesFiles.size) {
getPatterns(callBack);
}
}
} catch (err) {
logger.write("[ERROR] getCandles -> getCandlesWeAreIn -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
logger.write("[ERROR] getCandles -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
function getPatterns(callBack) {
try {
/*
We will read several files with pattern calculations for the current day. We will use these files as an input
to make trading decitions later.
*/
getMarketFiles();
function getMarketFiles() {
try {
/* Now we will get the market files */
for (i = 0; i < marketFilesPeriods.length; i++) {
let periodTime = marketFilesPeriods[i][0];
let periodName = marketFilesPeriods[i][1];
getFile(tomAzureFileStorage, "@AssetA_@AssetB.json", "@Exchange/Tom/dataSet.V1/Output/Candle-Stairs/Multi-Period-Market/@Period", periodName, undefined, onFileReceived, callBack);
function onFileReceived(file) {
thisObject.stairsFiles.set(periodName, file);
if (thisObject.stairsFiles.size === marketFilesPeriods.length) {
getDailyFiles();
}
}
}
} catch (err) {
logger.write("[ERROR] getPatterns -> getMarketFiles -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
function getDailyFiles() {
try {
for (i = 0; i < dailyFilePeriods.length; i++) {
let periodTime = dailyFilePeriods[i][0];
let periodName = dailyFilePeriods[i][1];
getFile(tomAzureFileStorage, "@AssetA_@AssetB.json", "@Exchange/Tom/dataSet.V1/Output/Candle-Stairs/Multi-Period-Daily/@Period/@Year/@Month/@Day", periodName, processDatetime, onFileReceived, callBack);
function onFileReceived(file) {
thisObject.stairsFiles.set(periodName, file);
if (thisObject.stairsFiles.size === dailyFilePeriods.length + marketFilesPeriods.length) {
getStairsWeAreIn();
}
}
}
} catch (err) {
logger.write("[ERROR] getPatterns -> getDailyFiles -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
function getStairsWeAreIn() {
try {
let counter = 0;
thisObject.stairsFiles.forEach(getCurrentStairs);
function getCurrentStairs(pStairsFile, pPeriodName, map) {
for (i = 0; i < pStairsFile.length; i++) {
let stairs = {
open: undefined,
close: undefined,
min: 10000000000000,
max: 0,
begin: undefined,
end: undefined,
direction: undefined,
candleCount: 0,
firstMin: 0,
firstMax: 0,
lastMin: 0,
lastMax: 0
};
stairs.open = pStairsFile[i][0];
stairs.close = pStairsFile[i][1];
stairs.min = pStairsFile[i][2];
stairs.max = pStairsFile[i][3];
stairs.begin = pStairsFile[i][4];
stairs.end = pStairsFile[i][5];
stairs.direction = pStairsFile[i][6];
stairs.candleCount = pStairsFile[i][7];
stairs.firstMin = pStairsFile[i][8];
stairs.firstMax = pStairsFile[i][9];
stairs.lastMin = pStairsFile[i][10];
stairs.lastMax = pStairsFile[i][11];
if (processDatetime.valueOf() >= stairs.begin && processDatetime.valueOf() <= stairs.end) {
thisObject.stairsMap.set(pPeriodName, stairs);
}
}
counter++;
if (counter === thisObject.stairsFiles.size) {
callBack(global.DEFAULT_OK_RESPONSE);
}
}
} catch (err) {
logger.write("[ERROR] getPatterns -> getStairsWeAreIn -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
logger.write("[ERROR] getPatterns -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
function getFile(pFileStorage, pFileName, pFilePath, pPeriodName, pDatetime, innerCallBack, outerCallBack) {
try {
if (FULL_LOG === true) { logger.write("[INFO] initialize -> getFile -> Entering function."); }
if (FULL_LOG === true) { logger.write("[INFO] initialize -> getFile -> pFileName = " + pFileName); }
if (FULL_LOG === true) { logger.write("[INFO] initialize -> getFile -> pFilePath = " + pFilePath); }
if (FULL_LOG === true) { logger.write("[INFO] initialize -> getFile -> pPeriodName = " + pPeriodName); }
if (FULL_LOG === true) { logger.write("[INFO] initialize -> getFile -> pDatetime = " + pDatetime); }
pFileName = pFileName.replace("@AssetA", MARKET.assetA);
pFileName = pFileName.replace("@AssetB", MARKET.assetB);
pFilePath = pFilePath.replace("@Exchange", global.EXCHANGE_NAME);
pFilePath = pFilePath.replace("@Period", pPeriodName);
if (pDatetime !== undefined) {
pFilePath = pFilePath.replace("@Year", pDatetime.getUTCFullYear());
pFilePath = pFilePath.replace("@Month", utilities.pad(pDatetime.getUTCMonth() + 1, 2));
pFilePath = pFilePath.replace("@Day", utilities.pad(pDatetime.getUTCDate(), 2));
}
pFileStorage.getTextFile(pFilePath, pFileName, onFileReceived);
function onFileReceived(err, text) {
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write("[ERROR] initialize -> getFile -> onFileReceived -> err = " + err.message);
outerCallBack(err);
return;
}
try {
let data = JSON.parse(text);
innerCallBack(data);
} catch (err) {
logger.write("[ERROR] initialize -> getFile -> onFileReceived -> Parsing JSON -> err = " + err.message);
outerCallBack(err);
return;
}
}
} catch (err) {
logger.write("[ERROR] initialize -> getFile -> err = " + err.message);
outerCallBack("Operation Failed");
}
}
} catch (err) {
logger.write("[ERROR] initialize -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
};