Merge pull request #133 from AAMasters/develop

Some refactoring + code from the trading engine
This commit is contained in:
Luis Fernando Molina authored and GitHub committed 2019-09-12 20:04:37 +02:00
commit 1116a4504d
25 files changed
+2359 -5982

No files matched your search

+55 -71
View File
@@ -1,9 +1,7 @@
exports.newAssistant = function newAssistant(BOT, logger, UTILITIES) {
/*
This module allows trading bots to execute actions on the exchange, and also on its current recorded state.
This module allows trading bots to execute actions on the exchange.
*/
const MODULE_NAME = "Assistant";
@@ -18,7 +16,7 @@
getPositions: getPositions,
getBalance: getBalance,
getAvailableBalance: getAvailableBalance,
getInvestment: getInvestment,
getInitialBalance: getInitialBalance,
getProfits: getProfits,
getCombinedProfits: getCombinedProfits,
getROI: getROI,
@@ -65,7 +63,8 @@
}
case 'Backtest': {
getMarketRateFromIndicator();
// getMarketRateFromIndicator(); NOTE: This path is disabled since for now we do not allow ticker in simulation. Also it allow us to ship a dataset without bruce
validateExchangeSyncronicity();
break;
}
@@ -114,13 +113,13 @@
validateExchangeSyncronicity();
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> getMarketRateFromExchange -> onTicker -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] initialize -> getMarketRateFromExchange -> onTicker -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> getMarketRateFromExchange -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] initialize -> getMarketRateFromExchange -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
@@ -158,12 +157,12 @@
let candleArray;
if (err.result === global.CUSTOM_FAIL_RESPONSE.result || err.code === "The specified key does not exist." || err.message === "File does not exist.") { // Just past midnight, this file will not exist for a couple of minutes.
logger.write(MODULE_NAME, "[WARN] initialize -> getMarketRateFromIndicator -> onFileReceived -> err = " + JSON.stringify(err));
logger.write(MODULE_NAME, "[WARN] initialize -> getMarketRateFromIndicator -> This could happen when there are still holes on trades and the process needs to catch up. ");
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return;
}
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
@@ -213,7 +212,7 @@
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> getMarketRateFromIndicator -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] initialize -> getMarketRateFromIndicator -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
@@ -255,13 +254,13 @@
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> validateExchangeSyncronicity -> onDone -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] initialize -> validateExchangeSyncronicity -> onDone -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> onDone -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] initialize -> onDone -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
@@ -274,15 +273,15 @@
/* Calculate Profits */
if (context.executionContext.investment.assetA > 0) {
if (context.executionContext.initialBalance.assetA > 0) {
context.executionContext.profits.assetA = (thisObject.truncDecimals(context.executionContext.balance.assetA) - thisObject.truncDecimals(context.executionContext.investment.assetA)) / thisObject.truncDecimals(context.executionContext.investment.assetA);
context.executionContext.profits.assetA = (thisObject.truncDecimals(context.executionContext.balance.assetA) - thisObject.truncDecimals(context.executionContext.initialBalance.assetA)) / thisObject.truncDecimals(context.executionContext.initialBalance.assetA);
context.executionContext.profits.assetA = thisObject.truncDecimals(context.executionContext.profits.assetA);
}
if (context.executionContext.investment.assetB > 0) {
if (context.executionContext.initialBalance.assetB > 0) {
context.executionContext.profits.assetB = (thisObject.truncDecimals(context.executionContext.balance.assetB) - thisObject.truncDecimals(context.executionContext.investment.assetB)) / thisObject.truncDecimals(context.executionContext.investment.assetB);
context.executionContext.profits.assetB = (thisObject.truncDecimals(context.executionContext.balance.assetB) - thisObject.truncDecimals(context.executionContext.initialBalance.assetB)) / thisObject.truncDecimals(context.executionContext.initialBalance.assetB);
context.executionContext.profits.assetB = thisObject.truncDecimals(context.executionContext.profits.assetB);
}
@@ -291,21 +290,21 @@
/* Calculate Combined Profits */
if (context.executionContext.investment.assetA > 0) {
if (context.executionContext.initialBalance.assetA > 0) {
let convertedAssetsB = (thisObject.truncDecimals(context.executionContext.balance.assetB) - thisObject.truncDecimals(context.executionContext.investment.assetB)) * marketRate;
let convertedAssetsB = (thisObject.truncDecimals(context.executionContext.balance.assetB) - thisObject.truncDecimals(context.executionContext.initialBalance.assetB)) * marketRate;
convertedAssetsB = thisObject.truncDecimals(convertedAssetsB);
context.executionContext.combinedProfits.assetA = (thisObject.truncDecimals(context.executionContext.balance.assetA) + convertedAssetsB - thisObject.truncDecimals(context.executionContext.investment.assetA)) / thisObject.truncDecimals(context.executionContext.investment.assetA) * 100;
context.executionContext.combinedProfits.assetA = (thisObject.truncDecimals(context.executionContext.balance.assetA) + convertedAssetsB - thisObject.truncDecimals(context.executionContext.initialBalance.assetA)) / thisObject.truncDecimals(context.executionContext.initialBalance.assetA) * 100;
context.executionContext.combinedProfits.assetA = thisObject.truncDecimals(context.executionContext.combinedProfits.assetA);
}
if (context.executionContext.investment.assetB > 0) {
if (context.executionContext.initialBalance.assetB > 0) {
let convertedAssetsA = (thisObject.truncDecimals(context.executionContext.balance.assetA) - thisObject.truncDecimals(context.executionContext.investment.assetA)) / marketRate;
let convertedAssetsA = (thisObject.truncDecimals(context.executionContext.balance.assetA) - thisObject.truncDecimals(context.executionContext.initialBalance.assetA)) / marketRate;
convertedAssetsA = thisObject.truncDecimals(convertedAssetsA);
context.executionContext.combinedProfits.assetB = (thisObject.truncDecimals(context.executionContext.balance.assetB) + convertedAssetsA - thisObject.truncDecimals(context.executionContext.investment.assetB)) / thisObject.truncDecimals(context.executionContext.investment.assetB) * 100;
context.executionContext.combinedProfits.assetB = (thisObject.truncDecimals(context.executionContext.balance.assetB) + convertedAssetsA - thisObject.truncDecimals(context.executionContext.initialBalance.assetB)) / thisObject.truncDecimals(context.executionContext.initialBalance.assetB) * 100;
context.executionContext.combinedProfits.assetB = thisObject.truncDecimals(context.executionContext.combinedProfits.assetB);
}
@@ -315,14 +314,14 @@
callBackFunction(global.DEFAULT_OK_RESPONSE);
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> calculateProfits -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] initialize -> calculateProfits -> err = " + err.stack);
callBack(global.DEFAULT_FAIL_RESPONSE);
return;
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
@@ -401,7 +400,7 @@
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] getPositionsAtExchange -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] getPositionsAtExchange -> err = " + err.stack);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
@@ -418,7 +417,7 @@
actions. Reasons why the positions might not be there are:
1. The user / account owner closed the positions manually.
2. The exchange for some eventuality closed the positions. In some exchanges positions have an expiration time.
2. The exchange for some reason closed the positions. In some exchanges positions have an expiration time.
3. The orders were executed.
Situations 1 and 2 are similar unexpected and we will stop the bot execution when we detect them. Number 3 is an
@@ -563,17 +562,17 @@
if (thisPosition.id === pPositionId) {
let feeRate = 0.002; // Default backtesting fee simulation
let feeRate = 0.002; // Default backtesting fee simulation
let trade = {
id: Math.trunc(Math.random(1) * 1000000),
type: thisPosition.type,
rate: thisPosition.rate.toString(),
let trade = {
id: Math.trunc(Math.random(1) * 1000000),
type: thisPosition.type,
rate: thisPosition.rate.toString(),
amountA: thisObject.truncDecimals(thisPosition.amountA).toString(),
amountB: thisObject.truncDecimals(thisPosition.amountB).toString(),
fee: thisObject.truncDecimals(feeRate).toString(),
date: (new Date()).valueOf()
}
date: (new Date()).valueOf()
}
trades.push(trade);
@@ -628,12 +627,12 @@
break;
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> onResponse -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> onResponse -> err = " + err.stack);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> err = " + err.stack);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
@@ -658,7 +657,7 @@
let sumRate = 0;
for (let k = 0; k < pTrades.length; k++) {
let trade = pTrades[k];
let trade = pTrades[k];
sumAssetA = sumAssetA + thisObject.truncDecimals(trade.amountA);
sumAssetB = sumAssetB + thisObject.truncDecimals(trade.amountB);
sumRate = sumRate + thisObject.truncDecimals(trade.rate);
@@ -706,7 +705,7 @@
next();
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> err = " + err.stack);
callBack(global.DEFAULT_FAIL_RESPONSE);
return;
}
@@ -728,8 +727,8 @@
let sumAssetA = 0;
let sumAssetB = 0;
for (let k = 0; k < pTrades.length; k++) {
let trade = pTrades[k];
for (let k = 0; k < pTrades.length; k++) {
let trade = pTrades[k];
sumAssetA = sumAssetA + thisObject.truncDecimals(trade.amountA);
sumAssetB = sumAssetB + thisObject.truncDecimals(trade.amountB);
}
@@ -751,7 +750,7 @@
*/
let exchangeParam = exchangeAPI.getMaxDecimalPositions();
let minValue = '0.' + (1).toPrecision(exchangeParam-1).split('.').reverse().join('');
let minValue = '0.' + (1).toPrecision(exchangeParam - 1).split('.').reverse().join('');
let exchangePrecision = parseFloat(parseFloat(minValue).toFixed(exchangeParam));
if (Math.abs(position.amountA - sumAssetA) > exchangePrecision || Math.abs(position.amountB - sumAssetB) > exchangePrecision) {
@@ -792,7 +791,7 @@
next();
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> err = " + err.stack);
callBack(global.DEFAULT_FAIL_RESPONSE);
return;
}
@@ -859,7 +858,7 @@
context.executionContext.balance.assetA = thisObject.truncDecimals(context.executionContext.balance.assetA + assetA);
context.executionContext.balance.assetB = thisObject.truncDecimals(context.executionContext.balance.assetB - assetB);
context.executionContext.availableBalance.assetA = thisObject.truncDecimals(context.executionContext.availableBalance.assetA + assetA);
context.executionContext.availableBalance.assetA = thisObject.truncDecimals(context.executionContext.availableBalance.assetA + assetA);
/* Not the available balance for asset B is not affected since it was already reduced when the order was placed. */
@@ -867,14 +866,14 @@
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> applyTradesToContext -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> applyTradesToContext -> err = " + err.stack);
callBack(global.DEFAULT_FAIL_RESPONSE);
return;
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> loopBody -> err = " + err.stack);
callBack(global.DEFAULT_FAIL_RESPONSE);
return;
}
@@ -913,7 +912,7 @@
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] ordersExecutionCheck -> err = " + err.stack);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
@@ -1077,12 +1076,12 @@
break;
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] putPosition -> onResponse -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] putPosition -> onResponse -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] putPosition -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] putPosition -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
@@ -1201,12 +1200,12 @@
break;
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] movePosition -> onResponse -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] movePosition -> onResponse -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] movePosition -> err = "+ err.stack);
logger.write(MODULE_NAME, "[ERROR] movePosition -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
@@ -1276,12 +1275,12 @@
return JSON.parse(JSON.stringify(context.executionContext.availableBalance));
}
function getInvestment() {
function getInitialBalance() {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getInvestment -> Entering function."); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getInvestment -> JSON.stringify(context.executionContext.investment) = " + JSON.stringify(context.executionContext.investment)); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getInitialBalance -> Entering function."); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getInitialBalance -> JSON.stringify(context.executionContext.initialBalance) = " + JSON.stringify(context.executionContext.initialBalance)); }
return JSON.parse(JSON.stringify(context.executionContext.investment));
return JSON.parse(JSON.stringify(context.executionContext.initialBalance));
}
function getProfits() {
@@ -1311,8 +1310,8 @@
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getROI -> Entering function."); }
let ROI = {
assetA: (context.executionContext.balance.assetA - context.executionContext.investment.assetA) / context.executionContext.investment.assetA * 100,
assetB: (context.executionContext.balance.assetB - context.executionContext.investment.assetB) / context.executionContext.investment.assetB * 100
assetA: (context.executionContext.balance.assetA - context.executionContext.initialBalance.assetA) / context.executionContext.initialBalance.assetA * 100,
assetB: (context.executionContext.balance.assetB - context.executionContext.initialBalance.assetB) / context.executionContext.initialBalance.assetB * 100
}
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] getROI -> JSON.stringify(ROI) = " + JSON.stringify(ROI)); }
@@ -1332,33 +1331,22 @@
let runIndex = context.statusReport.runs.length - 1;
context.newHistoryRecord.messageRelevance = pRelevance;
context.newHistoryRecord.messageTitle = bot.startMode + "." + runIndex +": "+ pTitle;
context.newHistoryRecord.messageTitle = bot.startMode + "." + runIndex + ": " + pTitle;
context.newHistoryRecord.messageBody = pBody;
}
function rememberThis(pKey, pValue) {
if (context.executionContext.remember === undefined) {
context.executionContext.remember = {};
}
context.executionContext.remember[pKey] = pValue;
}
function remindMeOf(pKey) {
if (context.executionContext.remember === undefined) {
context.executionContext.remember = {};
}
return context.executionContext.remember[pKey];
}
function sendEmail(pTitle, pBody, pTo) {
@@ -1367,15 +1355,11 @@
}
function addExtraData(pExtraDataArray) {
context.extraData.push(pExtraDataArray);
}
function truncDecimals(pFloatValue, pDecimals) {
if (!pDecimals) pDecimals = 8; // Default value
return parseFloat(parseFloat(pFloatValue).toFixed(pDecimals));
}
};
-2784
View File
File diff suppressed because it is too large. Load diff
+10 -10
View File
@@ -304,24 +304,24 @@
thisObject.executionHistory = [];
if (process.env.INITIAL_BALANCE_ASSET_A === undefined || process.env.INITIAL_BALANCE_ASSET_B === undefined) { throw new Error("Environment Variables INITIAL_INVESTMENT_A and INITIAL_INVESTMENT_B cannot be undefined.") }
if (process.env.INITIAL_BALANCE_ASSET_A === undefined || process.env.INITIAL_BALANCE_ASSET_B === undefined) { throw new Error("Environment Variables INITIAL_BALANCE_A and INITIAL_BALANCE_B cannot be undefined.") }
const INITIAL_INVESTMENT_A = Number(process.env.INITIAL_BALANCE_ASSET_A);
const INITIAL_INVESTMENT_B = Number(process.env.INITIAL_BALANCE_ASSET_B);
const INITIAL_BALANCE_A = Number(process.env.INITIAL_BALANCE_ASSET_A);
const INITIAL_BALANCE_B = Number(process.env.INITIAL_BALANCE_ASSET_B);
thisObject.executionContext = {
investment: { // This is used to calculate profits.
assetA: INITIAL_INVESTMENT_A,
assetB: INITIAL_INVESTMENT_B
initialBalance: { // This is used to calculate profits.
assetA: INITIAL_BALANCE_A,
assetB: INITIAL_BALANCE_B
},
balance: { // This is the total balance that includes positions at the order book + funds available to be traded.
assetA: INITIAL_INVESTMENT_A,
assetB: INITIAL_INVESTMENT_B // It starts with the initial investment.
assetA: INITIAL_BALANCE_A,
assetB: INITIAL_BALANCE_B // It starts with the initial initialBalance.
},
availableBalance: { // This is the balance the bot has at any moment in time available to be traded (not in positions at the order book).
assetA: INITIAL_INVESTMENT_A,
assetB: INITIAL_INVESTMENT_B // It starts with the initial investment.
assetA: INITIAL_BALANCE_A,
assetB: INITIAL_BALANCE_B // It starts with the initial initialBalance.
},
profits: {
assetA: 0,
+5 -1
View File
@@ -130,7 +130,11 @@ exports.newDebugLog = function newDebugLog() {
let logLine = '\r\n' + message;
if (process.env.CONSOLE_LOG === "true" || message.indexOf("ERROR") > 0) {
console.log(message)
let key = ''
if (thisObject.bot) {
key = thisObject.bot.devTeam + '-' + thisObject.bot.codeName + '-' + thisObject.bot.process
}
console.log(message + ' @ ' + key)
}
accumulatedLog = accumulatedLog + logLine;
+23 -11
View File
@@ -2,7 +2,7 @@
const ROOT_DIR = './';
const MODULE_NAME = "Indicator Bot Process Main Loop";
const MODULE_NAME = "Indicator Process Main Loop";
const FULL_LOG = true;
let USER_BOT_MODULE;
@@ -120,6 +120,9 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> Entering function."); }
/* Loop Heartbeat sent to the UI */
hearBeat()
/* We define here all the modules that the rest of the infraestructure, including the bots themselves can consume. */
const UTILITIES = require(ROOT_DIR + 'CloudUtilities');
@@ -791,6 +794,10 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Entering function."); }
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> nextWaitTime = " + nextWaitTime); }
/* We show we reached the end of the loop. */
hearBeat()
/* Here we check if we must stop the loop gracefully. */
shallWeStop(onStop, onContinue);
@@ -801,7 +808,7 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> onStop -> Stopping the Loop Gracefully. See you next time!"); }
if(global.FULL_LOG === 'true'){
if(global.WRITE_LOGS_TO_FILES === 'true'){
logger.persist();
}
@@ -819,9 +826,9 @@
switch (nextWaitTime) {
case 'Normal': {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.normalWaitTime / 1000) + " seconds."); }
checkLoopHealthHandle = setTimeout(checkLoopHealth, processConfig.normalWaitTime * 5, bot.loopCounter);
checkLoopHealthHandle = setTimeout(checkLoopHealth, processConfig.deadWaitTime * 5, bot.loopCounter);
nextLoopTimeoutHandle = setTimeout(loop, processConfig.normalWaitTime);
if(global.FULL_LOG === 'true'){
if(global.WRITE_LOGS_TO_FILES === 'true'){
logger.persist();
}
}
@@ -851,7 +858,7 @@
function checkLoopHealth(pLastLoop) {
if (bot.enableCheckLoopHealth === false) {
if (bot.enableCheckLoopHealth === false || global.STOP_TASK_GRACEFULLY === true) {
logger.write(MODULE_NAME, "[WARN] run -> loop -> checkLoopHealth -> bot.enableCheckLoopHealth = " + bot.enableCheckLoopHealth);
@@ -862,7 +869,7 @@
let now = new Date().valueOf();
if (now - bot.loopStartTime > processConfig.normalWaitTime) {
if (now - bot.loopStartTime > processConfig.deadWaitTime) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> checkLoopHealth -> Dead loop found -> pLastLoop = " + pLastLoop);
console.log((new Date().toISOString() + " [ERROR] run -> loop -> checkLoopHealth -> " + pad(bot.codeName,20) + " " + pad(bot.process,30) + " Loop # " + pad(Number(bot.loopCounter),5) + " found dead. Resurrecting it now."));
@@ -887,11 +894,7 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> shallWeStop -> Entering function. "); }
let stop = false
if (process.env.STOP_GRACEFULLY !== undefined)
stop = JSON.parse(process.env.STOP_GRACEFULLY)
if (!stop && global.SHALL_BOT_STOP === false) {
if (!global.STOP_TASK_GRACEFULLY) {
continueCallBack();
} else {
stopCallBack();
@@ -916,6 +919,15 @@
callBackFunction(err);
}
}
function hearBeat() {
let key = global.USER_DEFINITION.bot.processes[bot.processIndex].name + '-' + global.USER_DEFINITION.bot.processes[bot.processIndex].type + '-' + global.USER_DEFINITION.bot.processes[bot.processIndex].id
let event = {
seconds: (new Date()).getSeconds()
}
global.SYSTEM_EVENT_HANDLER.raiseEvent(key, 'Heartbeat', event)
}
} catch (err) {
parentLogger.write(MODULE_NAME, "[ERROR] run -> err = "+ err.stack);
clearInterval(fixedTimeLoopIntervalHandle);
+3 -3
View File
@@ -40,7 +40,7 @@ exports.newFileStorage = function newFileStorage(logger) {
if (logger) {
logger.write(MODULE_NAME, message);
} else {
console.log("['" + new Date().toISOString() + "', 0,'" + MODULE_NAME + "','" + message + "']")
//console.log("['" + new Date().toISOString() + "', 0,'" + MODULE_NAME + "','" + message + "']")
}
}
@@ -64,7 +64,7 @@ exports.newFileStorage = function newFileStorage(logger) {
}
logInfo('getTextFile: ' + fileLocation)
console.log('getTextFile: ' + fileLocation)
//console.log('getTextFile: ' + fileLocation)
let fileContent = await readFileAsync(fileLocation)
callBackFunction(global.DEFAULT_OK_RESPONSE, fileContent.toString())
@@ -130,7 +130,7 @@ exports.newFileStorage = function newFileStorage(logger) {
}
logInfo('createTextFile: ' + fileLocation)
console.log('createTextFile: ' + fileLocation)
//console.log('createTextFile: ' + fileLocation)
let directoryPath = fileLocation.substring(0, fileLocation.lastIndexOf('/') + 1);
mkDirByPathSync(directoryPath)
-51
View File
@@ -1,51 +0,0 @@
const axios = require('axios')
let fs = require('fs')
const { promisify } = require('util')
const readFileAsync = promisify(fs.readFile)
exports.getStrategy = async function () {
try {
if (!global.STRATEGY) {
let executionOnCloud = false
if (process.env.ON_CLOUD !== undefined) {
executionOnCloud = JSON.parse(process.env.ON_CLOUD)
}
if (executionOnCloud) {
const strategizerResponse = await axios({
url: process.env.GATEWAY_ENDPOINT_K8S,
method: 'post',
data: {
query: `
query($fbSlug: String!){
strategizer_TradingSystemByFb(fbSlug: $fbSlug){
data
}
}
`,
variables: {
fbSlug: process.env.BOT
}
},
headers: {
authorization: process.env.AUTHORIZATION
}
})
if (strategizerResponse.data.errors) {
throw new Error(strategizerResponse.data.errors[0].message)
}
global.STRATEGY = strategizerResponse.data.data.strategizer_TradingSystemByFb.data
} else {
let fileLocation = process.env.INTER_PROCESS_FILES_PATH + '/definition.json'
let strategy = await readFileAsync(fileLocation, { encoding: 'utf8' })
global.STRATEGY = JSON.parse(strategy)
}
}
return global.STRATEGY
} catch (error) {
throw new Error('There has been an error getting the strategy: ', JSON.stringify(error))
}
}
+1067
View File
File diff suppressed because it is too large. Load diff
+1 -11
View File
@@ -300,7 +300,7 @@
console.log(new Date().toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " " + " bot.multiPeriodDailyProcessDatetime = " + bot.multiPeriodDailyProcessDatetime.toISOString());
if (global.FULL_LOG === 'true') {
if (global.WRITE_LOGS_TO_FILES === 'true') {
logger.newInternalLoop(bot.codeName, bot.process);
}
@@ -372,16 +372,6 @@
}
}
let timePeriodFilter = global.EXECUTION_CONFIG.timePeriodFilter
if (timePeriodFilter !== undefined) {
if (timePeriodFilter.indexOf(outputPeriodLabel) === -1) {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> Discarding period for being filtered out. -> outputPeriodLabel = " + outputPeriodLabel); }
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> Discarding period for being filtered out. -> timePeriodFilter = " + timePeriodFilter); }
periodsControlLoop();
return;
}
}
let dependencyIndex = 0;
dataFiles = [];
-8
View File
@@ -143,14 +143,6 @@
let dependencyIndex = 0;
dataFiles = [];
let timePeriodFilter = global.EXECUTION_CONFIG.timePeriodFilter
if (timePeriodFilter !== undefined) {
if (timePeriodFilter.indexOf(outputPeriodLabel) === -1) {
periodsControlLoop();
return;
}
}
dependencyLoopBody();
function dependencyLoopBody() {
+7 -9
View File
@@ -6,14 +6,15 @@
<ProjectGuid>{ae0a3fe2-7021-4cc2-9922-a887ca5cdd7c}</ProjectGuid>
<ProjectHome />
<ProjectView>ShowAllFiles</ProjectView>
<StartupFile>Run.js</StartupFile>
<StartupFile>server.js</StartupFile>
<WorkingDirectory>.\</WorkingDirectory>
<OutputPath>.</OutputPath>
<ProjectTypeGuids>{3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{349c5851-65df-11da-9384-00065b846f21};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}</ProjectTypeGuids>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<Name>Project</Name>
<ScriptArguments>Trading-Process</ScriptArguments>
<ScriptArguments>
</ScriptArguments>
<NodeExePath>C:\Program Files\nodejs\node.exe</NodeExePath>
<StartWebBrowser>False</StartWebBrowser>
<LastActiveSolutionConfig>Debug|Any CPU</LastActiveSolutionConfig>
@@ -26,7 +27,9 @@
</Compile>
<Compile Include="Integrations\Ecosystem.js" />
<Compile Include="Integrations\FileStorage.js" />
<Compile Include="Integrations\Strategy.js" />
<Compile Include="MultiPeriod.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="MultiPeriodDaily.js">
<SubType>Code</SubType>
</Compile>
@@ -61,20 +64,15 @@
<Compile Include="IndicatorBotProcessMainLoop.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Run.js" />
<Compile Include="server.js" />
<Compile Include="StatusReport.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="TradingBotProcessMainLoop.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="CloudUtilities.js" />
</ItemGroup>
<ItemGroup>
<Content Include=".env" />
<Content Include=".gitignore" />
<Content Include="sequence - all processes.json" />
<Content Include="sequence.json" />
</ItemGroup>
<ItemGroup>
<Folder Include="Integrations\" />
+402 -658
View File
File diff suppressed because it is too large. Load diff
-398
View File
@@ -1,398 +0,0 @@
require('dotenv').config();
const strategy = require('./Integrations/Strategy');
const path = require('path');
global.SHALL_BOT_STOP = false
global.AT_BREAKPOINT = false // This is used only when running at the browser.
global.FULL_LOG = process.env.FULL_LOG
/* Default parameters can be changed by the execution configuration */
global.EXCHANGE_NAME = process.env.EXCHANGE_NAME
global.MARKET = { assetA: 'USDT', assetB: 'BTC' }
global.CLONE_EXECUTOR = { codeName: 'AACloud', version: '1.1' }
process.on('uncaughtException', function (err) {
console.log('[INFO] Run -> uncaughtException -> err.message = ' + err.message)
console.log('[INFO] Run -> uncaughtException -> err.stack = ' + err.stack)
process.exit(1)
})
process.on('unhandledRejection', (reason, p) => {
console.log('[INFO] Run -> unhandledRejection -> reason = ' + JSON.stringify(reason))
console.log('[INFO] Run -> unhandledRejection -> p = ' + JSON.stringify(p))
process.exit(1)
})
process.on('exit', function (code) {
console.log('[INFO] Run -> process.on.exit -> About to exit -> code = ' + code)
})
const definitionPath = path.resolve(process.env.INTER_PROCESS_FILES_PATH + '/definition.json');
const definition = require(definitionPath);
let sequenceList = require('./sequence');
let isRunSequence = false;
let sequenceStep = 0;
let processedSteps = new Map();
let notFirstSequence = false;
let runClonExecutor = true;
if (process.env.RUN_SEQUENCE !== undefined) {
isRunSequence = JSON.parse(process.env.RUN_SEQUENCE)
}
if (isRunSequence) {
process.on('message', message => {
if (message === 'STOP') {
runClonExecutor = false;
console.log("[INFO] CloneExecutor -> Clone Executor Stopped.");
}
});
sequenceExecution(sequenceStep)
} else {
readExecutionConfiguration()
}
function sequenceExecution(currentStep) {
let execution = sequenceList[currentStep];
process.env.STOP_GRACEFULLY = true;
execution.devTeam ? process.env.DEV_TEAM = execution.devTeam : undefined;
execution.bot ? process.env.BOT = execution.bot : undefined;
execution.mode ? process.env.START_MODE = execution.mode : undefined;
execution.resumeExecution = true;
execution.type ? process.env.TYPE = execution.type : undefined;
execution.process ? process.env.PROCESS = execution.process : undefined;
execution.startYear ? process.env.MIN_YEAR = execution.startYear : undefined;
execution.endYear ? process.env.MAX_YEAR = execution.endYear : undefined;
execution.month ? process.env.MONTH = execution.month : undefined;
execution.beginDatetime ? process.env.BEGIN_DATE_TIME = execution.beginDatetime : undefined;
execution.endDatetime ? process.env.END_DATE_TIME = execution.endDatetime : undefined;
execution.dataSet ? process.env.DATA_SET = execution.dataSet : undefined;
execution.timePeriod ? process.env.TIME_PERIOD = execution.timePeriod : undefined;
execution.baseAsset ? process.env.BASE_ASSET = execution.baseAsset : undefined;
execution.balanceAssetA ? process.env.INITIAL_BALANCE_ASSET_A = execution.balanceAssetA : undefined;
execution.balanceAssetB ? process.env.INITIAL_BALANCE_ASSET_B = execution.balanceAssetB : undefined;
execution.type === 'Trading' ? process.env.CLONE_ID = 1 : undefined;
execution.exchangeName ? global.EXCHANGE_NAME = execution.exchangeName : undefined;
if (definition) {
if (definition.personalData) {
if (definition.personalData.exchangeAccounts) {
if (definition.personalData.exchangeAccounts.length > 0) {
let exchangeAccount = definition.personalData.exchangeAccounts[0]
if (exchangeAccount.keys) {
if (exchangeAccount.keys.length > 0) {
let key = exchangeAccount.keys[0]
process.env.KEY = key.name
process.env.SECRET = key.code
}
}
}
}
}
}
let stepKey = execution.devTeam + '.' + execution.bot + '.' + execution.process;
if (processedSteps.has(stepKey)) {
processedSteps.set(stepKey, processedSteps.get(stepKey) + 1);
} else {
processedSteps.set(stepKey, 0);
}
readExecutionConfiguration(execution);
sequenceStep++;
}
function onExecutionFinish(result, finishStepKey) {
if (sequenceStep < sequenceList.length && runClonExecutor) {
sequenceExecution(sequenceStep);
} else {
setTimeout(function () {
if (runClonExecutor) {
console.log("[INFO] onExecutionFinish -> New round for sequence execution started.");
sequenceList = require('./sequence'); // We read again the sequence after every loop
sequenceStep = 0;
processedSteps = new Map();
notFirstSequence = true;
sequenceExecution(sequenceStep);
}
}, process.env.EXECUTION_LOOP_DELAY);
}
}
async function readExecutionConfiguration(execution) {
try {
console.log("[INFO] Run -> readExecutionConfiguration -> Entering function. ");
let timePeriodFilter
let botProcess
/* Try to get the begin and end dates from the Definition */
let definition = await strategy.getStrategy()
/* Dates are taken initially from .env, but can be overwritten if they are defined by the user */
let initialDatetime = process.env.BEGIN_DATE_TIME
let finalDatetime = process.env.END_DATE_TIME
if (execution.type === 'Trading-Engine') {
/* The Trading Engine only resumes its execution after the first sequence was completed. */
if (notFirstSequence === false) {
execution.resumeExecution = false
}
/* We set the START MODE of the Trading Engine */
if (process.env.KEY === undefined || process.env.SECRET === undefined) {
process.env.START_MODE = "backtest" // if we dont have keys, we swtich to backtest mode to avoid exchange errors.
} else {
process.env.START_MODE = "live" // If we have keys, then we are in live mode.
}
if (definition !== undefined) {
if (definition.simulationParams !== undefined) {
if (definition.simulationParams.beginDatetime !== undefined) {
initialDatetime = new Date(definition.simulationParams.beginDatetime) /* The first override occurs here, with the simulation parameters */
}
/* Here we only look for one timePeriod, in the future we will be able to process the whole array, but not for now. */
if (definition.simulationParams.timePeriodDailyArray !== undefined) {
if (definition.simulationParams.timePeriodDailyArray.length === 1) {
timePeriodFilter = definition.simulationParams.timePeriodDailyArray[0]
botProcess = "Multi-Period-Daily"
}
}
if (definition.simulationParams.timePeriodMarketArray !== undefined) {
if (definition.simulationParams.timePeriodMarketArray.length === 1) {
timePeriodFilter = definition.simulationParams.timePeriodMarketArray[0]
botProcess = "Multi-Period-Market"
}
}
}
if (definition.tradingSystem !== undefined) {
if (definition.tradingSystem.parameters !== undefined) {
if (definition.tradingSystem.parameters.baseAsset !== undefined) {
if (definition.tradingSystem.parameters.baseAsset.formula !== undefined) {
if (definition.tradingSystem.parameters.baseAsset.formula.code !== undefined) {
let code = JSON.parse(definition.tradingSystem.parameters.baseAsset.formula.code)
if (code.initialDatetime !== undefined) {
initialDatetime = code.initialDatetime /* The second override occurs here, with the date explicitelly defined by the user */
}
if (code.finalDatetime !== undefined) {
finalDatetime = code.finalDatetime
}
}
}
}
}
}
/* Get the initial balance from the definition */
let tradingSystem = definition.tradingSystem
if (tradingSystem) {
if (tradingSystem.parameters !== undefined) {
if (tradingSystem.parameters.baseAsset !== undefined) {
if (tradingSystem.parameters.baseAsset.formula !== undefined) {
let receivedParameters
try {
receivedParameters = JSON.parse(tradingSystem.parameters.baseAsset.formula.code);
if (receivedParameters.name !== undefined) {
baseAsset = receivedParameters.name;
if (baseAsset !== 'BTC' && baseAsset !== 'USDT') {
/* using BTC as default */
baseAsset = 'BTC'
}
}
if (baseAsset === 'BTC') { // NOTE: POLONIEX, the only exchange working so far, has Asset A and B inverted. We need to fix this.
if (receivedParameters.initialBalance !== undefined) {
process.env.INITIAL_BALANCE_ASSET_B = receivedParameters.initialBalance;
process.env.INITIAL_BALANCE_ASSET_A = 0
}
} else {
if (receivedParameters.initialBalance !== undefined) {
process.env.INITIAL_BALANCE_ASSET_A = receivedParameters.initialBalance;
process.env.INITIAL_BALANCE_ASSET_B = 0
}
}
} catch (err) {
process.env.INITIAL_BALANCE_ASSET_A = 0 // default
process.env.INITIAL_BALANCE_ASSET_B = 0.001 // default
}
}
}
}
}
}
}
let startMode
// General Financial Being Configuration
global.DEV_TEAM = process.env.DEV_TEAM
global.CURRENT_BOT_REPO = process.env.BOT + "-" + process.env.TYPE + "-Bot"
if (process.env.TYPE === 'Trading' || process.env.TYPE === 'Trading-Engine') {
let live = {
run: 'false',
resumeExecution: execution.resumeExecution,
beginDatetime: new Date(definition.simulationParams.timestamp).toISOString(),
endDatetime: finalDatetime
}
let backtest = {
run: 'false',
resumeExecution: execution.resumeExecution,
beginDatetime: initialDatetime,
endDatetime: finalDatetime
}
let competition = {
run: 'false',
resumeExecution: execution.resumeExecution,
beginDatetime: initialDatetime,
endDatetime: finalDatetime
}
startMode = {
live: live,
backtest: backtest,
competition: competition
}
} else if (process.env.TYPE === 'Indicator' || process.env.TYPE === 'Sensor') {
let allMonths = {
run: "false",
minYear: process.env.MIN_YEAR,
maxYear: process.env.MAX_YEAR
}
let oneMonth = {
run: "false",
year: process.env.MIN_YEAR,
month: process.env.MONTH
}
let noTime = {
run: "false",
beginDatetime: process.env.BEGIN_DATE_TIME,
resumeExecution: execution.resumeExecution
}
let fixedInterval = {
run: "false",
interval: process.env.INTERVAL
}
startMode = {
allMonths: allMonths,
oneMonth: oneMonth,
noTime: noTime,
fixedInterval: fixedInterval
}
} else {
console.log("[ERROR] readExecutionConfiguration -> Bot Type is invalid.");
throw new Error("readExecutionConfiguration -> Bot Type is invalid.")
}
startMode[process.env.START_MODE].run = "true"
if (botProcess === undefined) { botProcess = process.env.PROCESS } // Only use the .env when nothing comes at Definition.json
let cloneToExecute = {
enabled: "true",
devTeam: process.env.DEV_TEAM,
bot: process.env.BOT,
process: botProcess,
repo: global.CURRENT_BOT_REPO
}
let timePeriod
if (timePeriodFilter === undefined) {
timePeriod = process.env.TIME_PERIOD
} else {
timePeriod = timePeriodFilter
}
global.EXECUTION_CONFIG = {
cloneToExecute: cloneToExecute,
startMode: startMode,
timePeriod: getTimePeriod(timePeriod),
timePeriodFileStorage: timePeriod,
timePeriodFilter: timePeriodFilter,
dataSet: process.env.DATA_SET
};
timePeriodFilter = undefined
timePeriod = undefined
global.CLONE_EXECUTOR = {
codeName: 'AACloud',
version: '1.1'
}
startRoot();
}
catch (err) {
console.log("[ERROR] readExecutionConfiguration -> err = " + err.stack);
console.log("[ERROR] readExecutionConfiguration -> Please verify that the Start Mode for the type of Bot configured applies to that type.");
}
}
function getTimePeriod(timePeriod) {
if (timePeriod !== undefined) {
try {
let timePeriodMap = new Map()
timePeriodMap.set('24-hs', 86400000)
timePeriodMap.set('12-hs', 43200000)
timePeriodMap.set('08-hs', 28800000)
timePeriodMap.set('06-hs', 21600000)
timePeriodMap.set('04-hs', 14400000)
timePeriodMap.set('03-hs', 10800000)
timePeriodMap.set('02-hs', 7200000)
timePeriodMap.set('01-hs', 3600000)
timePeriodMap.set('45-min', 2700000)
timePeriodMap.set('40-min', 2400000)
timePeriodMap.set('30-min', 1800000)
timePeriodMap.set('20-min', 1200000)
timePeriodMap.set('15-min', 900000)
timePeriodMap.set('10-min', 600000)
timePeriodMap.set('05-min', 300000)
timePeriodMap.set('04-min', 240000)
timePeriodMap.set('03-min', 180000)
timePeriodMap.set('02-min', 120000)
timePeriodMap.set('01-min', 60000)
return timePeriodMap.get(timePeriod)
} catch (error) {
console.log('[WARN] Run -> readExecutionConfiguration -> getTimePeriod -> Error: ', error)
}
} else {
return undefined
}
}
function startRoot() {
console.log('[INFO] Run -> startRoot -> Entering function. ')
const ROOT_DIR = './'
const ROOT_MODULE = require(ROOT_DIR + 'Root')
let root = ROOT_MODULE.newRoot()
let UI_COMMANDS = {
beginDatetime: undefined,
endDatetime: undefined,
timePeriod: undefined,
startMode: undefined,
eventHandler: undefined
}
root.initialize(UI_COMMANDS, onInitialized)
function onInitialized() {
console.log('[INFO] Run -> startRoot -> onInitialized -> Entering function. ')
root.start(onExecutionFinish)
}
}
+28 -12
View File
@@ -2,7 +2,7 @@
const ROOT_DIR = './';
const MODULE_NAME = "Sensor Bot Process Main Loop";
const MODULE_NAME = "Sensor Process Main Loop";
const FULL_LOG = true;
let USER_BOT_MODULE;
@@ -51,6 +51,9 @@
return;
}
USER_BOT_MODULE = {}
if (bot.process === "Hole-Fixing") {
//USER_BOT_MODULE.newUserBot = require(process.env.BOTS_PATH + '/aamasters/AAMasters/bots/AACharly-Sensor-Bot/Hole-Fixing/User.Bot').newUserBot
}
USER_BOT_MODULE.newUserBot = eval(text); // TODO This needs to be changed function
filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo;
@@ -66,6 +69,7 @@
return;
}
COMMONS_MODULE = {}
COMMONS_MODULE.newCommons = eval(text); // TODO This needs to be changed function
callBackFunction(global.DEFAULT_OK_RESPONSE);
@@ -118,6 +122,9 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> Entering function."); }
/* Loop Heartbeat sent to the UI */
hearBeat()
/* We define here all the modules that the rest of the infraestructure, including the bots themselves can consume. */
const UTILITIES = require(ROOT_DIR + 'CloudUtilities');
@@ -536,6 +543,10 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Entering function."); }
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> nextWaitTime = " + nextWaitTime); }
/* We show we reached the end of the loop. */
hearBeat()
/* Here we check if we must stop the loop gracefully. */
shallWeStop(onStop, onContinue);
@@ -546,7 +557,7 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> onStop -> Stopping the Loop Gracefully. See you next time!"); }
if(global.FULL_LOG === 'true'){
if(global.WRITE_LOGS_TO_FILES === 'true'){
logger.persist();
}
@@ -570,15 +581,15 @@
if (bot.runAtFixedInterval === true) {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Fixed Interval Normal exit point reached."); }
checkLoopHealthHandle = setTimeout(checkLoopHealth, bot.fixedInterval * 5, bot.loopCounter);
if(global.FULL_LOG === 'true'){
if(global.WRITE_LOGS_TO_FILES === 'true'){
logger.persist();
}
return;
} else {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.normalWaitTime / 1000) + " seconds."); }
checkLoopHealthHandle = setTimeout(checkLoopHealth, processConfig.normalWaitTime * 5, bot.loopCounter);
checkLoopHealthHandle = setTimeout(checkLoopHealth, processConfig.deadWaitTime * 5, bot.loopCounter);
nextLoopTimeoutHandle = setTimeout(loop, processConfig.normalWaitTime);
if(global.FULL_LOG === 'true'){
if(global.WRITE_LOGS_TO_FILES === 'true'){
logger.persist();
}
}
@@ -621,7 +632,7 @@
function checkLoopHealth(pLastLoop) {
if (bot.enableCheckLoopHealth === false) {
if (bot.enableCheckLoopHealth === false || global.STOP_TASK_GRACEFULLY === true) {
logger.write(MODULE_NAME, "[WARN] run -> loop -> checkLoopHealth -> bot.enableCheckLoopHealth = " + bot.enableCheckLoopHealth);
@@ -632,7 +643,7 @@
let now = new Date().valueOf();
if (now - bot.loopStartTime > processConfig.normalWaitTime) {
if (now - bot.loopStartTime > processConfig.deadWaitTime) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> checkLoopHealth -> Dead loop found -> pLastLoop = " + pLastLoop);
console.log((new Date().toISOString() + " [ERROR] run -> loop -> checkLoopHealth -> " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " Loop # " + pad(Number(bot.loopCounter), 5) + " found dead. Resurrecting it now."));
@@ -657,11 +668,7 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> shallWeStop -> Entering function. "); }
let stop = false
if (process.env.STOP_GRACEFULLY !== undefined)
stop = JSON.parse(process.env.STOP_GRACEFULLY)
if (!stop && global.SHALL_BOT_STOP === false) {
if (!global.STOP_TASK_GRACEFULLY) {
continueCallBack();
} else {
stopCallBack();
@@ -687,6 +694,15 @@
callBackFunction(err);
}
}
function hearBeat() {
let key = global.USER_DEFINITION.bot.processes[bot.processIndex].name + '-' + global.USER_DEFINITION.bot.processes[bot.processIndex].type + '-' + global.USER_DEFINITION.bot.processes[bot.processIndex].id
let event = {
seconds: (new Date()).getSeconds()
}
global.SYSTEM_EVENT_HANDLER.raiseEvent(key, 'Heartbeat', event)
}
}
catch (err) {
+47 -1
View File
@@ -54,7 +54,49 @@
timePath = "/" + year + "/" + month;
}
callBackFunction(global.DEFAULT_OK_RESPONSE);
if (owner.waitUntilNextUpdate === true) {
/* This forces this process to wait until the process that this one depends on, updates its status report. */
let extraCallerId = ''
if (pMonth) { extraCallerId = extraCallerId + '-' + pMonth }
if (pYear) { extraCallerId = extraCallerId + '-' + pYear }
let key = owner.devTeam + "-" + owner.bot + "-" + owner.process
let callerId = bot.devTeam + "-" + bot.codeName + "-" + bot.process + extraCallerId
let subscriptionIdStatusReport
subscriptionIdStatusReport = global.SYSTEM_EVENT_HANDLER.listenToEvent(key, 'Status Report Updated', undefined, callerId, responseCallBack, eventsCallBack)
function responseCallBack(message) {
if (message.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] initialize -> Could not register event listener for event 'Status Report Updated' -> Message = " + message);
let event = {
reason: 'This process depends on ' + key + ' which is currently not running.'
}
global.SYSTEM_EVENT_HANDLER.raiseEvent(key, 'Process Terminated', event)
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function eventsCallBack() {
/* We continue the normal flow after we learn the dependent process has updated its status report. */
stopListening()
callBackFunction(global.DEFAULT_OK_RESPONSE);
}
function stopListening() {
if (subscriptionIdStatusReport) {
stopListening(key, 'Status Report Updated', subscriptionIdStatusReport)
}
}
} else {
/* In this case, the Status Report does not depends on a process which needs to wait for. */
callBackFunction(global.DEFAULT_OK_RESPONSE);
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> err = "+ err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
@@ -199,6 +241,10 @@
logger.write(MODULE_NAME, "[INFO] save -> onFileCreated -> Content written = " + fileContent);
}
/* Here we raise the event stating that this status report was updated. */
let key = bot.devTeam + "-" + bot.codeName + "-" + bot.process
global.SYSTEM_EVENT_HANDLER.raiseEvent(key, 'Status Report Updated')
callBackFunction(global.DEFAULT_OK_RESPONSE);
return;
}
+178
View File
@@ -0,0 +1,178 @@
exports.newSystemEventHandler = function newSystemEventHandler(ipc) {
let thisObject = {
initialize: initialize,
finalize: finalize,
createEventHandler: createEventHandler,
deleteEventHandler: deleteEventHandler,
listenToEvent: listenToEvent,
stopListening: stopListening,
raiseEvent: raiseEvent
}
let eventListeners = new Map()
let responseWaiters = new Map()
ipc.config.id = 'Task Server';
ipc.config.retry = 1500;
ipc.config.silent = true;
return thisObject
function initialize(canllerName, callBackFunction) {
ipc.connectTo(
'world',
function () {
ipc.of.world.on(
'connect',
function () {
ipc.log('## Connected to Superalgos Event Server ##'.rainbow, ipc.config.delay);
let eventCommand = {
action: 'greetings',
from: canllerName
}
sendCommand(eventCommand)
callBackFunction()
}
);
ipc.of.world.on(
'disconnect',
function () {
ipc.log('Disconnected from Superalgos Event Server '.notice);
}
);
ipc.of.world.on(
'message', // here is where all incomming messages are processed.
function (data) {
ipc.log('Got a message from Superalgos Event Server: '.debug, data);
let message = JSON.parse(data)
if (message.action === 'Event Raised') {
let key
if (message.callerId) {
key = message.eventHandlerName + '-' + message.eventType + '-' + message.callerId
} else {
key = message.eventHandlerName + '-' + message.eventType
}
let handler = eventListeners.get(key)
if (handler) {
handler.callBack(message)
} else {
console.log(key + ' not found so could not deliver event raised.')
console.log(' Message = ' + data)
}
return
}
if (message.action === 'Event Server Response') {
let handler = responseWaiters.get(message.callerId)
if (handler) {
handler(message)
}
return
}
}
);
}
);
}
function finalize() {
/* Before disconnecting we will forze all eventListeners to stop listening. */
const eventListenersArray = [...eventListeners.values()]
for (let i = 0; i < eventListenersArray.length; i++) {
let handler = eventListenersArray[i]
let eventCommand = {
action: 'stopListening',
eventHandlerName: handler.eventHandlerName,
eventType: handler.eventType,
callerId: handler.callerId
}
sendCommand(eventCommand)
}
ipc.disconnect('world');
}
function sendCommand(command, responseCallBack, eventsCallBack) {
if (command.action === 'listenToEvent') {
let key
if (command.callerId) {
key = command.eventHandlerName + '-' + command.eventType + '-' + command.callerId
} else {
key = command.eventHandlerName + '-' + command.eventType
}
let handler = {
eventHandlerName: command.eventHandlerName,
eventType: command.eventType,
callerId: command.callerId,
callBack: eventsCallBack
}
eventListeners.set(key, handler)
}
if (command.callerId && responseCallBack) {
responseWaiters.set(command.callerId, responseCallBack)
}
ipc.of.world.emit(
'message',
JSON.stringify(command)
)
}
function createEventHandler(eventHandlerName, callerId, responseCallBack) {
let eventCommand = {
action: 'createEventHandler',
eventHandlerName: eventHandlerName,
callerId: callerId
}
sendCommand(eventCommand, responseCallBack)
}
function deleteEventHandler(eventHandlerName, callerId, responseCallBack) {
let eventCommand = {
action: 'deleteEventHandler',
eventHandlerName: eventHandlerName,
callerId: callerId
}
sendCommand(eventCommand, responseCallBack)
}
function listenToEvent(eventHandlerName, eventType, extraData, callerId, responseCallBack, eventsCallBack) {
let eventCommand = {
action: 'listenToEvent',
eventHandlerName: eventHandlerName,
eventType: eventType,
extraData: extraData,
callerId: callerId
}
sendCommand(eventCommand, responseCallBack, eventsCallBack)
}
function stopListening(eventHandlerName, eventType, eventSubscriptionId, callerId, responseCallBack) {
/* User either needs to specify a valid eventSubscriptionId OR the 3 params: eventHandlerName, eventType, callerId which were used when start listening to events. */
let eventCommand = {
action: 'stopListening',
eventHandlerName: eventHandlerName,
eventType: eventType,
eventSubscriptionId: eventSubscriptionId,
callerId: callerId
}
sendCommand(eventCommand, responseCallBack)
}
function raiseEvent(eventHandlerName, eventType, event, callerId, responseCallBack) {
let eventCommand = {
action: 'raiseEvent',
eventHandlerName: eventHandlerName,
eventType: eventType,
event: event,
callerId: callerId
}
sendCommand(eventCommand, responseCallBack)
}
}
+25
View File
@@ -0,0 +1,25 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2027
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "Project", "Project.njsproj", "{AE0A3FE2-7021-4CC2-9922-A887CA5CDD7C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{AE0A3FE2-7021-4CC2-9922-A887CA5CDD7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AE0A3FE2-7021-4CC2-9922-A887CA5CDD7C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AE0A3FE2-7021-4CC2-9922-A887CA5CDD7C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AE0A3FE2-7021-4CC2-9922-A887CA5CDD7C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9128DF06-8CA5-497C-8BF7-B924571C5394}
EndGlobalSection
EndGlobal
File diff suppressed because it is too large. Load diff
+102 -18
View File
@@ -10,7 +10,9 @@
const MULTI_PERIOD_MARKET = require(ROOT_DIR + 'MultiPeriodMarket');
const MULTI_PERIOD_DAILY = require(ROOT_DIR + 'MultiPeriodDaily');
const MULTI_PERIOD = require(ROOT_DIR + 'MultiPeriod');
const FILE_STORAGE = require('./Integrations/FileStorage.js');
let fileStorage = FILE_STORAGE.newFileStorage(parentLogger);
const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog');
@@ -54,7 +56,7 @@
}
USER_BOT_MODULE = {}
//USER_BOT_MODULE.newUserBot = require(ROOT_DIR + 'User.Bot').newUserBot // Use this for a better debugging experience. You need to bring this js module to this folder in order to work.
//USER_BOT_MODULE.newUserBot = require(process.env.BOTS_PATH + '/aamasters/AAMasters/bots/AAJason-Trading-Engine-Bot/Multi-Period/User.Bot').newUserBot // Use this for a better debugging experience. You need to bring this js module to this folder in order to work.
USER_BOT_MODULE.newUserBot = eval(text); // Use this for production
filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo;
@@ -69,8 +71,9 @@
callBackFunction(global.DEFAULT_OK_RESPONSE);
return;
}
COMMONS_MODULE = {}
//COMMONS_MODULE.newCommons = require(ROOT_DIR + 'Commons').newCommons // Use this for a better debugging experience. You need to bring this js module to this folder in order to work.
//COMMONS_MODULE.newCommons = require(process.env.BOTS_PATH + '/aamasters/AAMasters/bots/AAJason-Trading-Engine-Bot/Commons').newCommons // Use this for a better debugging experience. You need to bring this js module to this folder in order to work.
COMMONS_MODULE.newCommons = eval(text); // Use this for production
callBackFunction(global.DEFAULT_OK_RESPONSE);
@@ -91,17 +94,72 @@
bot.enableCheckLoopHealth = true;
let fixedTimeLoopIntervalHandle;
global.STOP_PROCESSING = true;
if (bot.runAtFixedInterval === true) {
global.SYSTEM_EVENT_HANDLER.listenToEvent('Cockpit-Restart-Button', 'Backstesting Started', undefined, undefined, undefined, startBackTesting)
global.SYSTEM_EVENT_HANDLER.listenToEvent('Cockpit-Restart-Button', 'Live-Trading Started', undefined, undefined, undefined, startLiveTrading)
global.SYSTEM_EVENT_HANDLER.listenToEvent('Cockpit-Restart-Button', 'Stop Requested', undefined, undefined, undefined, stopRequested)
fixedTimeLoopIntervalHandle = setInterval(loop, bot.fixedInterval);
function startBackTesting(message) {
} else {
/* We are going to run the Definition comming at the event. */
global.DEFINITION = JSON.parse(message.event.definition)
loop();
bot.startMode = "Backtest"
processConfig.framework.startDate.resumeExecution = false;
global.STOP_PROCESSING = false
bot.hasTheBotJustStarted = true
/* If we can not get for any reason the initial date of the backtest, we will start at present time. */
processConfig.framework.startDate.fixedDate = new Date()
/* If we received simulation params we use them instead. */
if (global.DEFINITION.simulationParams) {
if (global.DEFINITION.simulationParams.beginDatetime) {
processConfig.framework.startDate.fixedDate = global.DEFINITION.simulationParams.beginDatetime
}
}
/* We finally will try to exctact the initial and final date for the backtest from the Definition */
if (global.DEFINITION.tradingSystem !== undefined) {
if (global.DEFINITION.tradingSystem.parameters !== undefined) {
if (global.DEFINITION.tradingSystem.parameters.timeRange !== undefined) {
if (global.DEFINITION.tradingSystem.parameters.timeRange.code !== undefined) {
try {
let code = JSON.parse(global.DEFINITION.tradingSystem.parameters.timeRange.code)
if (code.initialDatetime !== undefined) {
processConfig.framework.startDate.fixedDate = code.initialDatetime /* The second override occurs here, with the date explicitelly defined by the user */
}
if (code.finalDatetime !== undefined) {
processConfig.framework.endDate.fixedDate = code.finalDatetime
}
} catch (err) {
global.DEFINITION.tradingSystem.parameters.timeRange.error = err.message
}
}
}
}
}
}
function startLiveTrading(message) {
/* We are going to run the Definition comming at the event. */
global.DEFINITION = JSON.parse(message.event.definition)
bot.startMode = "Live"
processConfig.framework.startDate.fixedDate = new Date()
processConfig.framework.startDate.resumeExecution = false;
global.STOP_PROCESSING = false
bot.hasTheBotJustStarted = true
}
function stopRequested() {
global.STOP_PROCESSING = true
}
loop();
function loop() {
try {
@@ -122,6 +180,11 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> Entering function."); }
let nextWaitTime;
/* Loop Heartbeat sent to the UI */
hearBeat()
/* We define here all the modules that the rest of the infraestructure, including the bots themselves can consume. */
const UTILITIES = require(ROOT_DIR + 'CloudUtilities');
@@ -142,6 +205,15 @@
console.log(new Date().toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30)
+ " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8));
/* Checking if we should process this loop or not.*/
if (global.STOP_PROCESSING === true) {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> We are going to skip this Loop bacause we were requested to stop or never asked to start."); }
console.log("[INFO] run -> loop -> We are going to skip this Loop bacause we were requested to stop or never asked to start.")
nextWaitTime = 'Normal';
loopControl(nextWaitTime);
return
}
/* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */
let userBot;
@@ -149,8 +221,6 @@
let statusDependencies;
let dataDependencies;
let nextWaitTime;
initializeStatusDependencies();
function initializeStatusDependencies() {
@@ -485,6 +555,11 @@
intitializeProcessFramework();
break;
}
case 'Multi-Period': {
processFramework = MULTI_PERIOD.newMultiPeriod(bot, logger, COMMONS_MODULE, UTILITIES, USER_BOT_MODULE, COMMONS_MODULE);
intitializeProcessFramework();
break;
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeAssistant -> onInizialized -> Process Framework not Supported.");
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeAssistant -> onInizialized -> Process Framework Name = " + processConfig.framework.name);
@@ -862,6 +937,10 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Entering function."); }
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> nextWaitTime = " + nextWaitTime); }
/* We show we reached the end of the loop. */
hearBeat()
/* Here we check if we must stop the loop gracefully. */
shallWeStop(onStop, onContinue);
@@ -872,7 +951,7 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> onStop -> Stopping the Loop Gracefully. See you next time!"); }
if (global.FULL_LOG === 'true') {
if (global.WRITE_LOGS_TO_FILES === 'true') {
logger.persist();
}
@@ -890,9 +969,9 @@
switch (nextWaitTime) {
case 'Normal': {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.normalWaitTime / 1000) + " seconds."); }
checkLoopHealthHandle = setTimeout(checkLoopHealth, processConfig.normalWaitTime * 5, bot.loopCounter);
checkLoopHealthHandle = setTimeout(checkLoopHealth, processConfig.deadWaitTime * 5, bot.loopCounter);
nextLoopTimeoutHandle = setTimeout(loop, processConfig.normalWaitTime);
if (global.FULL_LOG === 'true') {
if (global.WRITE_LOGS_TO_FILES === 'true') {
logger.persist();
}
}
@@ -922,7 +1001,7 @@
function checkLoopHealth(pLastLoop) {
if (bot.enableCheckLoopHealth === false) {
if (bot.enableCheckLoopHealth === false || global.STOP_TASK_GRACEFULLY === true) {
logger.write(MODULE_NAME, "[WARN] run -> loop -> checkLoopHealth -> bot.enableCheckLoopHealth = " + bot.enableCheckLoopHealth);
@@ -933,7 +1012,7 @@
let now = new Date().valueOf();
if (now - bot.loopStartTime > processConfig.normalWaitTime) {
if (now - bot.loopStartTime > processConfig.deadWaitTime) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> checkLoopHealth -> Dead loop found -> pLastLoop = " + pLastLoop);
console.log((new Date().toISOString() + " [ERROR] run -> loop -> checkLoopHealth -> " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " Loop # " + pad(Number(bot.loopCounter), 5) + " found dead. Resurrecting it now."));
@@ -958,11 +1037,7 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> shallWeStop -> Entering function. "); }
let stop = false
if (process.env.STOP_GRACEFULLY !== undefined)
stop = JSON.parse(process.env.STOP_GRACEFULLY)
if (!stop && global.SHALL_BOT_STOP === false) {
if (!global.STOP_TASK_GRACEFULLY) {
continueCallBack();
} else {
stopCallBack();
@@ -988,6 +1063,15 @@
callBackFunction(err);
}
}
function hearBeat() {
let key = global.USER_DEFINITION.bot.processes[bot.processIndex].name + '-' + global.USER_DEFINITION.bot.processes[bot.processIndex].type + '-' + global.USER_DEFINITION.bot.processes[bot.processIndex].id
let event = {
seconds: (new Date()).getSeconds()
}
global.SYSTEM_EVENT_HANDLER.raiseEvent(key, 'Heartbeat', event)
}
} catch (err) {
parentLogger.write(MODULE_NAME, "[ERROR] run -> err = "+ err.stack);
clearInterval(fixedTimeLoopIntervalHandle);
-558
View File
@@ -1,558 +0,0 @@
exports.newUserBot = function newUserBot(bot, logger, COMMONS, UTILITIES, fileStorage) {
const FULL_LOG = true;
const LOG_FILE_CONTENT = false;
const MODULE_NAME = "User Bot";
const EXECUTION_FOLDER_NAME = "Trading-Execution";
const SIMULATED_RECORDS_FOLDER_NAME = "Trading-Simulation";
const CONDITIONS_FOLDER_NAME = "Simulation-Conditions";
const STRATEGIES_FOLDER_NAME = "Simulation-Strategies";
const TRADES_FOLDER_NAME = "Simulation-Trades";
const commons = COMMONS.newCommons(bot, logger, UTILITIES);
thisObject = {
initialize: initialize,
start: start
};
let utilities = UTILITIES.newCloudUtilities(bot, logger);
let dataDependencies;
let assistant;
return thisObject;
function initialize(pDataDependencies, callBackFunction, pAssistant) {
try {
logger.fileName = MODULE_NAME;
logger.initialize();
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); }
dataDependencies = pDataDependencies;
assistant = pAssistant;
callBackFunction(global.DEFAULT_OK_RESPONSE);
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function start(dataFiles, timePeriod, outputPeriodLabel, currentDay, startDate, endDate, interExecutionMemory, callBackFunction) {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); }
let market = global.MARKET;
let dataFile;
let recordsArray
let conditionsArray
let strategiesArray
let tradesArray
let lastObjectsArray
let tradingSystem = {};
commons.initializeData();
for (let i = 0; i < dataDependencies.config.length; i++) {
let dependency = dataDependencies.config[i];
dataFile = dataFiles[i];
switch (i) {
/*
case 0: {
commons.buildLRC(dataFile, callBackFunction);
break;
}*/
case 0: {
commons.buildPercentageBandwidthMap(dataFile, callBackFunction);
break;
}
case 1: {
commons.buildBollingerBandsMap(dataFile, callBackFunction);
break;
}
case 2: {
commons.buildBollingerChannelsArray(dataFile, callBackFunction);
break;
}
case 3: {
commons.buildBollingerSubChannelsArray(dataFile, callBackFunction);
break;
}
case 4: {
commons.buildCandles(dataFile, callBackFunction);
break;
}
}
}
commons.runSimulation(
timePeriod,
currentDay,
startDate,
endDate,
interExecutionMemory,
assistant,
writeFiles,
callBackFunction)
function writeFiles(pTradingSystem, pExecutionArray, pRecordsArray, pConditionsArray, pStrategiesArray, pTradesArray, pLastObjectsArray) {
tradingSystem = pTradingSystem
executionArray = pExecutionArray
recordsArray = pRecordsArray
conditionsArray = pConditionsArray
strategiesArray = pStrategiesArray
tradesArray = pTradesArray
lastObjectsArray = pLastObjectsArray
writeExecutionFile()
}
function writeExecutionFile() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> Entering function."); }
let separator = "";
let fileRecordCounter = 0;
let fileContent = "";
for (let i = 0; i < executionArray.length; i++) {
let record = executionArray[i];
/* Will only add to the file the records of the current day */
if (record.begin < currentDay.valueOf()) { continue; }
fileContent = fileContent + separator + '[' +
record.begin + "," +
record.end + "," +
JSON.stringify(record.executionRecord) + "]";
if (separator === "") { separator = ","; }
fileRecordCounter++;
}
fileContent = "[" + fileContent + "]";
let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2);
let fileName = '' + market.assetA + '_' + market.assetB + '.json';
let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion;
let filePath = filePathRoot + "/Output/" + EXECUTION_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath;
filePath += '/' + fileName
fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated);
function onFileCreated(err) {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> onFileCreated -> Entering function."); }
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeExecutionFile -> onFileCreated -> fileContent = " + fileContent); }
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> err = " + err.stack);
logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> filePath = " + filePath);
logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB);
callBackFunction(err);
return;
}
writeRecordsFile();
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> onFileCreated -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> writeExecutionFile -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function writeRecordsFile() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeRecordsFile -> Entering function."); }
let separator = "";
let fileRecordCounter = 0;
let fileContent = "";
for (let i = 0; i < recordsArray.length; i++) {
let record = recordsArray[i];
/* Will only add to the file the records of the current day */
if (record.begin < currentDay.valueOf()) { continue; }
fileContent = fileContent + separator + '[' +
record.begin + "," +
record.end + "," +
record.type + "," +
record.marketRate + "," +
record.amount + "," +
record.balanceA + "," +
record.balanceB + "," +
record.profit + "," +
record.lastTradeProfitLoss + "," +
record.stopLoss + "," +
record.roundtrips + "," +
record.hits + "," +
record.fails + "," +
record.hitRatio + "," +
record.ROI + "," +
record.periods + "," +
record.days + "," +
record.anualizedRateOfReturn + "," +
record.positionRate + "," +
record.lastTradeROI + "," +
record.strategy + "," +
record.strategyStageNumber + "," +
record.takeProfit + "," +
record.stopLossPhase + "," +
record.takeProfitPhase + "," +
JSON.stringify(record.executionRecord) + "," +
record.positionSize + "," +
record.initialBalanceA + "," +
record.minimumBalanceA + "," +
record.maximumBalanceA + "," +
record.initialBalanceB + "," +
record.minimumBalanceB + "," +
record.maximumBalanceB + "," +
record.baseAsset + "," +
record.positionPeriods + "," +
record.positionDays + "]";
if (separator === "") { separator = ","; }
fileRecordCounter++;
}
fileContent = "[" + fileContent + "]";
let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2);
let fileName = '' + market.assetA + '_' + market.assetB + '.json';
let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion;
let filePath = filePathRoot + "/Output/" + SIMULATED_RECORDS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath;
filePath += '/' + fileName
fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated);
function onFileCreated(err) {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeRecordsFile -> onFileCreated -> Entering function."); }
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeRecordsFile -> onFileCreated -> fileContent = " + fileContent); }
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.stack);
logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> filePath = " + filePath);
logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB);
callBackFunction(err);
return;
}
writeConditionsFile();
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> onFileCreated -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> writeRecordsFile -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function writeConditionsFile() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeConditionsFile -> Entering function."); }
let separator = "";
let fileRecordCounter = 0;
let fileContent = "";
for (let i = 0; i < conditionsArray.length; i++) {
let record = conditionsArray[i];
/* Will only add to the file the records of the current day */
if (record.begin < currentDay.valueOf()) { continue; }
let conditions = "";
let conditionsSeparator = "";
/* Will only add to the file the records of the current day */
if (record.begin < currentDay.valueOf()) { continue; }
for (let j = 0; j < record.length - 3; j++) {
conditions = conditions + conditionsSeparator + record[j];
if (conditionsSeparator === "") { conditionsSeparator = ","; }
}
conditions = conditions + conditionsSeparator + '[' + record[record.length - 3] + ']'; // The last item contains an Array of condition values.
conditions = conditions + conditionsSeparator + '[' + record[record.length - 2] + ']'; // The last item contains an Array of formulaErrors.
conditions = conditions + conditionsSeparator + '[' + record[record.length - 1] + ']'; // The last item contains an Array of formulaValues.
fileContent = fileContent + separator + '[' + conditions + ']';
if (separator === "") { separator = ","; }
fileRecordCounter++;
}
fileContent = "[" + fileContent + "]";
fileContent = "[" + JSON.stringify(tradingSystem) + "," + JSON.stringify(lastObjectsArray) + "," + fileContent + "]";
let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2);
let fileName = '' + market.assetA + '_' + market.assetB + '.json';
let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion;
let filePath = filePathRoot + "/Output/" + CONDITIONS_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath;
filePath += '/' + fileName
fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated);
function onFileCreated(err) {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeConditionsFile -> onFileCreated -> Entering function."); }
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeConditionsFile -> onFileCreated -> fileContent = " + fileContent); }
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.stack);
logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> filePath = " + filePath);
logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB);
callBackFunction(err);
return;
}
writeStrategiesFile();
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> onFileCreated -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> writeConditionsFile -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function writeStrategiesFile() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStrategiesFile -> Entering function."); }
let separator = "";
let fileRecordCounter = 0;
let fileContent = "";
for (let i = 0; i < strategiesArray.length; i++) {
let record = strategiesArray[i];
/* Will only add to the file the records of the current day. In this case since objects can span more than one day, we add all of the objects that ends
at the current date. */
if (record.end < currentDay.valueOf()) { continue; }
fileContent = fileContent + separator + '[' +
record.begin + "," +
record.end + "," +
record.status + "," +
record.number + "," +
record.beginRate + "," +
record.endRate + "]";
if (separator === "") { separator = ","; }
fileRecordCounter++;
}
fileContent = "[" + fileContent + "]";
let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2);
let fileName = '' + market.assetA + '_' + market.assetB + '.json';
let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion;
let filePath = filePathRoot + "/Output/" + STRATEGIES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath;
filePath += '/' + fileName
fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated);
function onFileCreated(err) {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStrategiesFile -> onFileCreated -> Entering function."); }
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStrategiesFile -> onFileCreated -> fileContent = " + fileContent); }
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.stack);
logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> filePath = " + filePath);
logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB);
callBackFunction(err);
return;
}
writeTradesFile();
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> onFileCreated -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> writeStrategiesFile -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function writeTradesFile() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeTradesFile -> Entering function."); }
let separator = "";
let fileRecordCounter = 0;
let fileContent = "";
for (let i = 0; i < tradesArray.length; i++) {
let record = tradesArray[i];
/* Will only add to the file the records of the current day. In this case since objects can span more than one day, we add all of the objects that ends
at the current date. */
if (record.end < currentDay.valueOf()) { continue; }
if (record.stopRate === undefined) { record.stopRate = 0}
fileContent = fileContent + separator + '[' +
record.begin + "," +
record.end + "," +
record.status + "," +
record.lastTradeROI + "," +
record.beginRate + "," +
record.endRate + "," +
record.exitType + "," +
record.stopRate + "]";
if (separator === "") { separator = ","; }
fileRecordCounter++;
}
fileContent = "[" + fileContent + "]";
let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2);
let fileName = '' + market.assetA + '_' + market.assetB + '.json';
let filePathRoot = bot.devTeam + "/" + bot.codeName + "." + bot.version.major + "." + bot.version.minor + "/" + global.CLONE_EXECUTOR.codeName + "." + global.CLONE_EXECUTOR.version + "/" + global.EXCHANGE_NAME + "/" + bot.dataSetVersion;
let filePath = filePathRoot + "/Output/" + TRADES_FOLDER_NAME + "/" + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath;
filePath += '/' + fileName
fileStorage.createTextFile(bot.devTeam, filePath, fileContent + '\n', onFileCreated);
function onFileCreated(err) {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeTradesFile -> onFileCreated -> Entering function."); }
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> writeTradesFile -> onFileCreated -> fileContent = " + fileContent); }
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.stack);
logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> filePath = " + filePath);
logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> market = " + market.assetA + "_" + market.assetB);
callBackFunction(err);
return;
}
callBackFunction(global.DEFAULT_OK_RESPONSE);
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> onFileCreated -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> writeTradesFile -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
};
+33
View File
@@ -202,6 +202,11 @@
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.0.0.tgz",
"integrity": "sha512-30xVGqjLjiUOArT4+M5q9sYdvuR4riM6yK9wMcas9Vbp6zZa+ocC9dp6QoftuhTPhFAiLK/0C5Ni2nou/Bk8lg=="
},
"easy-stack": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.0.tgz",
"integrity": "sha1-EskbMIWjfwuqM26UhurEv5Tj54g="
},
"ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
@@ -224,6 +229,11 @@
"resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz",
"integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA=="
},
"event-pubsub": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/event-pubsub/-/event-pubsub-4.3.0.tgz",
"integrity": "sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ=="
},
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
@@ -344,6 +354,19 @@
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
},
"js-message": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/js-message/-/js-message-1.0.5.tgz",
"integrity": "sha1-IwDSSxrwjondCVvBpMnJz8uJLRU="
},
"js-queue": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/js-queue/-/js-queue-2.0.0.tgz",
"integrity": "sha1-NiITz4YPRo8BJfxslqvBdCUx+Ug=",
"requires": {
"easy-stack": "1.0.0"
}
},
"jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
@@ -435,6 +458,16 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"node-ipc": {
"version": "9.1.1",
"resolved": "https://registry.npmjs.org/node-ipc/-/node-ipc-9.1.1.tgz",
"integrity": "sha512-FAyICv0sIRJxVp3GW5fzgaf9jwwRQxAKDJlmNFUL5hOy+W4X/I5AypyHoq0DXXbo9o/gt79gj++4cMr4jVWE/w==",
"requires": {
"event-pubsub": "4.3.0",
"js-message": "1.0.5",
"js-queue": "2.0.0"
}
},
"nonce": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/nonce/-/nonce-1.0.4.tgz",
+1
View File
@@ -17,6 +17,7 @@
"@superalgos/mqservice": "^0.0.17",
"axios": "^0.19.0",
"dotenv": "^8.0.0",
"node-ipc": "^9.1.1",
"winston": "^3.2.1"
}
}
-192
View File
@@ -1,192 +0,0 @@
[
{
"devTeam": "AAMasters",
"bot": "AACharly",
"mode": "noTime",
"resumeExecution": true,
"type": "Sensor",
"exchangeName": "Poloniex",
"process": "Live-Trades",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AACharly",
"mode": "noTime",
"resumeExecution": true,
"type": "Sensor",
"exchangeName": "Poloniex",
"process": "Hole-Fixing",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AABruce",
"mode": "noTime",
"resumeExecution": true,
"type": "Indicator",
"exchangeName": "Poloniex",
"process": "Single-Period-Daily",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AAOlivia",
"mode": "noTime",
"resumeExecution": true,
"type": "Indicator",
"exchangeName": "Poloniex",
"process": "Multi-Period-Daily",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AAOlivia",
"mode": "noTime",
"resumeExecution": true,
"type": "Indicator",
"exchangeName": "Poloniex",
"process": "Multi-Period-Market",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AATom",
"mode": "noTime",
"resumeExecution": true,
"type": "Indicator",
"exchangeName": "Poloniex",
"process": "Multi-Period-Daily",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AATom",
"mode": "noTime",
"resumeExecution": true,
"type": "Indicator",
"exchangeName": "Poloniex",
"process": "Multi-Period-Market",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AAChris",
"mode": "noTime",
"resumeExecution": true,
"type": "Indicator",
"exchangeName": "Poloniex",
"process": "Multi-Period-Daily",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AAChris",
"mode": "noTime",
"resumeExecution": true,
"type": "Indicator",
"exchangeName": "Poloniex",
"process": "Multi-Period-Market",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AAPaula",
"mode": "noTime",
"resumeExecution": true,
"type": "Indicator",
"exchangeName": "Poloniex",
"process": "Multi-Period-Daily",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AAPaula",
"mode": "noTime",
"resumeExecution": true,
"type": "Indicator",
"exchangeName": "Poloniex",
"process": "Multi-Period-Market",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AAJason",
"mode": "live",
"resumeExecution": true,
"type": "Trading-Engine",
"exchangeName": "Poloniex",
"process": "Multi-Period-Daily",
"beginDatetime": "2019-08-01T08:00:00.000Z",
"timePeriod": "05-min"
},
{
"devTeam": "AAVikings",
"bot": "AAGauss",
"mode": "noTime",
"resumeExecution": true,
"type": "Indicator",
"exchangeName": "Poloniex",
"process": "Multi-Period-Daily",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAVikings",
"bot": "AAGauss",
"mode": "noTime",
"resumeExecution": true,
"type": "Indicator",
"exchangeName": "Poloniex",
"process": "Multi-Period-Market",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "vikingsalerts",
"bot": "simulator-bot-vikingsalerts",
"mode": "noTime",
"resumeExecution": true,
"type": "Indicator",
"exchangeName": "Poloniex",
"process": "Multi-Period-Daily",
"beginDatetime": "2019-08-01T08:00:00.000Z",
"timePeriod": "05-min"
},
{
"devTeam": "vikingsalerts",
"bot": "bot-vikingsalerts",
"mode": "live",
"resumeExecution": true,
"type": "Trading",
"exchangeName": "Poloniex",
"process": "Trading-Process",
"beginDatetime": "2019-08-01T08:00:00.000Z",
"timePeriod": "05-min",
"dataSet": "Multi-Period-Daily"
}
]
-145
View File
@@ -1,145 +0,0 @@
[
{
"devTeam": "AAMasters",
"bot": "AACharly",
"mode": "noTime",
"resumeExecution": true,
"type": "Sensor",
"exchangeName": "Poloniex",
"process": "Live-Trades",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AACharly",
"mode": "noTime",
"resumeExecution": true,
"type": "Sensor",
"exchangeName": "Poloniex",
"process": "Hole-Fixing",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AABruce",
"mode": "noTime",
"resumeExecution": true,
"type": "Indicator",
"exchangeName": "Poloniex",
"process": "Single-Period-Daily",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AAOlivia",
"mode": "noTime",
"resumeExecution": true,
"type": "Indicator",
"exchangeName": "Poloniex",
"process": "Multi-Period-Daily",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AAOlivia",
"mode": "noTime",
"resumeExecution": true,
"type": "Indicator",
"exchangeName": "Poloniex",
"process": "Multi-Period-Market",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AATom",
"mode": "noTime",
"resumeExecution": true,
"type": "Indicator",
"exchangeName": "Poloniex",
"process": "Multi-Period-Daily",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AATom",
"mode": "noTime",
"resumeExecution": true,
"type": "Indicator",
"exchangeName": "Poloniex",
"process": "Multi-Period-Market",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AAChris",
"mode": "noTime",
"resumeExecution": true,
"type": "Indicator",
"exchangeName": "Poloniex",
"process": "Multi-Period-Daily",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AAChris",
"mode": "noTime",
"resumeExecution": true,
"type": "Indicator",
"exchangeName": "Poloniex",
"process": "Multi-Period-Market",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AAPaula",
"mode": "noTime",
"resumeExecution": true,
"type": "Indicator",
"exchangeName": "Poloniex",
"process": "Multi-Period-Daily",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AAPaula",
"mode": "noTime",
"resumeExecution": true,
"type": "Indicator",
"exchangeName": "Poloniex",
"process": "Multi-Period-Market",
"startYear": 2019,
"endYear": 2021,
"month": 1
},
{
"devTeam": "AAMasters",
"bot": "AAJason",
"mode": "live",
"resumeExecution": true,
"type": "Trading-Engine",
"exchangeName": "Poloniex",
"process": "Multi-Period-Daily",
"beginDatetime": "2019-08-01T08:00:00.000Z",
"timePeriod": "05-min"
}
]
+372
View File
@@ -0,0 +1,372 @@
/* Callbacks default responses. */
global.DEFAULT_OK_RESPONSE = {
result: "Ok",
message: "Operation Succeeded"
};
global.DEFAULT_FAIL_RESPONSE = {
result: "Fail",
message: "Operation Failed"
};
global.DEFAULT_RETRY_RESPONSE = {
result: "Retry",
message: "Retry Later"
};
global.CUSTOM_OK_RESPONSE = {
result: "Ok, but check Message",
message: "Custom Message"
};
global.CUSTOM_FAIL_RESPONSE = {
result: "Fail Because",
message: "Custom Message"
};
/* Process Events */
process.on('uncaughtException', function (err) {
console.log('[INFO] Task Server -> server -> uncaughtException -> err.message = ' + err.message)
console.log('[INFO] Task Server -> server -> uncaughtException -> err.stack = ' + err.stack)
process.exit(1)
})
process.on('unhandledRejection', (reason, p) => {
console.log('[INFO] Task Server -> server -> unhandledRejection -> reason = ' + JSON.stringify(reason))
console.log('[INFO] Task Server -> server -> unhandledRejection -> p = ' + JSON.stringify(p))
process.exit(1)
})
process.on('exit', function (code) {
console.log('[INFO] Task Server -> server -> process.on.exit -> About to exit -> code = ' + code)
})
/* Local Variables */
let sequenceList = []
let heartBeatInterval
/*
We read the first string sent as an argument when the process was created by the Task Manager. Ther we will find the information of the identity
of this Task and know exactly what to run within this server instance.
*/
global.USER_DEFINITION = process.argv[2]
if (global.USER_DEFINITION !== undefined) {
console.log('[INFO] Task Server -> server -> global.USER_DEFINITION = ' + global.USER_DEFINITION)
try {
global.USER_DEFINITION = JSON.parse(global.USER_DEFINITION)
} catch (err) {
console.log('[ERROR] Task Server -> server -> global.USER_DEFINITION -> ' + err.stack)
}
}
else { // I use this section to debug in standalone mode.
let argument = ' {"type":"Task","name":"Runs Backtests, Fordwardtests & Live Trades ","bot":{"type":"Trading Engine","processes":[{"type":"Process","name":"Multi Period","code":{"devTeam":"AAMasters","bot":"AAJason","mode":"live","resumeExecution":true,"type":"Trading-Engine","exchangeName":"Poloniex","process":"Multi-Period-Daily","beginDatetime":"2019-08-01T08:00:00.000Z","timePeriod":"05-min"},"id":"1bfce24d-8c05-4be9-bd25-328f07c85265"}]},"id":"cbb13086-608d-4bb4-960a-17a81038877b"}'
try {
global.USER_DEFINITION = JSON.parse(argument)
} catch (err) {
console.log(err.stack)
}
}
require('dotenv').config();
global.DEFINITION = require(process.env.INTER_PROCESS_FILES_PATH + '/Definition');
global.WRITE_LOGS_TO_FILES = process.env.WRITE_LOGS_TO_FILES
/* Default parameters can be changed by the execution configuration */
global.EXCHANGE_NAME = process.env.EXCHANGE_NAME
global.MARKET = { assetA: 'USDT', assetB: 'BTC' }
global.CLONE_EXECUTOR = { codeName: 'AACloud', version: '1.1' }
/*
We need to count how many process instances we deployd and how many of them have already finished their job, either
because they just finished or because there was a request to stop the proceses. In this way, once we reach the
amount of instances started, we can safelly destroy the rest of the objects running and let this nodejs process die.
*/
global.ENDED_PROCESSES_COUNTER = 0
global.TOTAL_PROCESS_INSTANCES_CREATED = 0
/* Here we listen for the message to stop this Task / Process comming from the Task Manager, which is the paret of this node js process. */
process.on('message', message => {
if (message === 'Stop this Task') {
global.STOP_TASK_GRACEFULLY = true;
global.STOP_PROCESSING = true
/*
There are some process that might no be able to end grafully, for example the ones schedulle to process information in a future day or month.
In order to be sure that the process will be terminated, we schedulle one forced exit in 2 minutes from now.
*/
console.log('[INFO] Task Server -> server -> process.on -> Executing order received from Task Manager to Stop this Task. Nodejs process will be exited in less than 2 minutes.')
setTimeout(global.EXIT_NODE_PROCESS, 120000);
}
});
global.EXIT_NODE_PROCESS = function exitProcess() {
/* Cleaning Before Exiting. */
clearInterval(global.HEARTBEAT_INTERVAL_HANDLER)
for (let i = 0; i < global.USER_DEFINITION.bot.processes.length; i++) {
let code = global.USER_DEFINITION.bot.processes[i].code
/* Delete the event handler for each process. */
let key = code.devTeam + "-" + code.codeName + "-" + code.process
let event = {
reason: 'Signal Received to Terminate this Process.'
}
global.SYSTEM_EVENT_HANDLER.raiseEvent(key, 'Process Terminated', event)
global.SYSTEM_EVENT_HANDLER.deleteEventHandler(key)
}
global.SYSTEM_EVENT_HANDLER.finalize()
global.SYSTEM_EVENT_HANDLER = undefined
console.log("[INFO] Task Server -> " + global.USER_DEFINITION.name + " -> EXIT_NODE_PROCESS -> Task Server Stopped.");
process.exit()
}
let notFirstSequence = false;
/* Setting up the global Event Handler */
const EVENT_HANDLER_MODULE = require('./SystemEventHandler.js');
const IPC = require('node-ipc');
global.SYSTEM_EVENT_HANDLER = EVENT_HANDLER_MODULE.newSystemEventHandler(IPC)
global.SYSTEM_EVENT_HANDLER.initialize('Task Server', bootLoader)
function bootLoader() {
for (let i = 0; i < global.USER_DEFINITION.bot.processes.length; i++) {
let code = global.USER_DEFINITION.bot.processes[i].code
/* Add to the execution sequence list. */
sequenceList.push(code)
/* Create the event handler for each process. This event handlers are where the status reports updated events are raised. */
let key = code.devTeam + "-" + code.bot + "-" + code.process
global.SYSTEM_EVENT_HANDLER.createEventHandler(key)
}
/* Heartbeat sent to the UI */
let key = global.USER_DEFINITION.name + '-' + global.USER_DEFINITION.type + '-' + global.USER_DEFINITION.id
global.SYSTEM_EVENT_HANDLER.createEventHandler(key)
global.HEARTBEAT_INTERVAL_HANDLER = setInterval(hearBeat, 1000)
function hearBeat() {
/* The heartbeat event is raised at the event handler of the instance of this task, created at the UI. */
let event = {
seconds: (new Date()).getSeconds()
}
global.SYSTEM_EVENT_HANDLER.raiseEvent(key, 'Heartbeat', event)
}
startSequence()
}
/* Old Run.js code follows... */
function startSequence() {
for (let processIndex = 0; processIndex < global.USER_DEFINITION.bot.processes.length; processIndex++) {
let execution = sequenceList[processIndex];
global.STOP_TASK_GRACEFULLY = false;
execution.devTeam ? process.env.DEV_TEAM = execution.devTeam : undefined;
execution.bot ? process.env.BOT = execution.bot : undefined;
execution.resumeExecution = true;
execution.type ? process.env.TYPE = execution.type : undefined;
execution.process ? process.env.PROCESS = execution.process : undefined;
execution.baseAsset ? process.env.BASE_ASSET = execution.baseAsset : undefined;
execution.balanceAssetA ? process.env.INITIAL_BALANCE_ASSET_A = execution.balanceAssetA : undefined;
execution.balanceAssetB ? process.env.INITIAL_BALANCE_ASSET_B = execution.balanceAssetB : undefined;
execution.type === 'Trading' ? process.env.CLONE_ID = 1 : undefined;
execution.exchangeName ? global.EXCHANGE_NAME = execution.exchangeName : undefined;
if (global.DEFINITION) {
if (global.DEFINITION.personalData) {
if (global.DEFINITION.personalData.exchangeAccounts) {
if (global.DEFINITION.personalData.exchangeAccounts.length > 0) {
let exchangeAccount = global.DEFINITION.personalData.exchangeAccounts[0]
if (exchangeAccount.keys) {
if (exchangeAccount.keys.length > 0) {
let key = exchangeAccount.keys[0]
process.env.KEY = key.name
process.env.SECRET = key.code
}
}
}
}
}
}
readExecutionConfiguration(execution, processIndex);
}
}
async function readExecutionConfiguration(execution, processIndex) {
try {
console.log("[INFO] Task Server -> server -> readExecutionConfiguration -> Entering function. ");
let botProcess
if (execution.type === 'Trading-Engine') {
/* The Trading Engine only resumes its execution after the first sequence was completed. */
if (notFirstSequence === false) {
execution.resumeExecution = false
}
if (global.DEFINITION !== undefined) {
botProcess = "Multi-Period"
/* Get the initial balance from the global.DEFINITION */
let tradingSystem = global.DEFINITION.tradingSystem
if (tradingSystem) {
if (tradingSystem.parameters !== undefined) {
if (tradingSystem.parameters.baseAsset !== undefined) {
let code
try {
code = JSON.parse(tradingSystem.parameters.baseAsset.code);
if (code.name !== undefined) {
baseAsset = code.name;
if (baseAsset !== 'BTC' && baseAsset !== 'USDT') {
/* using BTC as default */
baseAsset = 'BTC'
}
}
if (baseAsset === 'BTC') { // NOTE: POLONIEX, the only exchange working so far, has Asset A and B inverted. We need to fix this.
if (code.initialBalance !== undefined) {
process.env.INITIAL_BALANCE_ASSET_B = code.initialBalance;
process.env.INITIAL_BALANCE_ASSET_A = 0
}
} else {
if (code.initialBalance !== undefined) {
process.env.INITIAL_BALANCE_ASSET_A = code.initialBalance;
process.env.INITIAL_BALANCE_ASSET_B = 0
}
}
} catch (err) {
global.DEFINITION.tradingSystem.parameters.baseAsset.error = err.message
process.env.INITIAL_BALANCE_ASSET_A = 0 // default
process.env.INITIAL_BALANCE_ASSET_B = 0.001 // default
}
}
}
}
}
}
// General Financial Being Configuration
global.DEV_TEAM = process.env.DEV_TEAM
global.CURRENT_BOT_REPO = process.env.BOT + "-" + process.env.TYPE + "-Bot"
if (botProcess === undefined) { botProcess = process.env.PROCESS } // Only use the .env when nothing comes at Definition.json
let cloneToExecute = {
enabled: "true",
devTeam: process.env.DEV_TEAM,
bot: process.env.BOT,
process: botProcess,
repo: global.CURRENT_BOT_REPO
}
global.EXECUTION_CONFIG = {
cloneToExecute: cloneToExecute
};
global.CLONE_EXECUTOR = {
codeName: 'AACloud',
version: '1.1'
}
startRoot(processIndex);
}
catch (err) {
console.log("[ERROR] readExecutionConfiguration -> err = " + err.stack);
console.log("[ERROR] readExecutionConfiguration -> Please verify that the Start Mode for the type of Bot configured applies to that type.");
}
}
function getTimePeriod(timePeriod) {
if (timePeriod !== undefined) {
try {
let timePeriodMap = new Map()
timePeriodMap.set('24-hs', 86400000)
timePeriodMap.set('12-hs', 43200000)
timePeriodMap.set('08-hs', 28800000)
timePeriodMap.set('06-hs', 21600000)
timePeriodMap.set('04-hs', 14400000)
timePeriodMap.set('03-hs', 10800000)
timePeriodMap.set('02-hs', 7200000)
timePeriodMap.set('01-hs', 3600000)
timePeriodMap.set('45-min', 2700000)
timePeriodMap.set('40-min', 2400000)
timePeriodMap.set('30-min', 1800000)
timePeriodMap.set('20-min', 1200000)
timePeriodMap.set('15-min', 900000)
timePeriodMap.set('10-min', 600000)
timePeriodMap.set('05-min', 300000)
timePeriodMap.set('04-min', 240000)
timePeriodMap.set('03-min', 180000)
timePeriodMap.set('02-min', 120000)
timePeriodMap.set('01-min', 60000)
return timePeriodMap.get(timePeriod)
} catch (error) {
console.log('[WARN] Task Server -> server -> readExecutionConfiguration -> getTimePeriod -> Error: ', error)
}
} else {
return undefined
}
}
function startRoot(processIndex) {
console.log('[INFO] Task Server -> server -> startRoot -> Entering function. ')
const ROOT_DIR = './'
const ROOT_MODULE = require(ROOT_DIR + 'Root')
let root = ROOT_MODULE.newRoot()
let UI_COMMANDS = {
beginDatetime: undefined,
endDatetime: undefined,
timePeriod: undefined,
startMode: undefined,
eventHandler: undefined
}
root.initialize(UI_COMMANDS, onInitialized)
function onInitialized() {
console.log('[INFO] Task Server -> server -> startRoot -> onInitialized -> Entering function. ')
root.start(processIndex)
}
}