Merge remote-tracking branch 'upstream/develop' into develop

This commit is contained in:
Luis Fernando Molina committed 2019-03-26 13:42:48 +01:00
commit 13a84f1d17
36 files changed
+3195 -1287

No files matched your search

+12 -83
View File
@@ -182,7 +182,9 @@
end: candleArray[i][5]
};
if (bot.processDatetime.valueOf() >= candle.begin && bot.processDatetime.valueOf() < candle.end) {
// TODO condition added for when there is no market rate available.
if ((bot.processDatetime.valueOf() >= candle.begin && bot.processDatetime.valueOf() < candle.end)
|| (i + 1) === candleArray.length) {
marketRate = (candle.open + candle.close) / 2;
marketRate = thisObject.truncDecimals(marketRate);
@@ -198,7 +200,6 @@
return;
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> getMarketRateFromIndicator -> onFileReceived -> err = " + err.message);
logger.write(MODULE_NAME, "[ERROR] initialize -> getMarketRateFromIndicator -> onFileReceived -> Asuming this is a temporary situation. Requesting a Retry.");
@@ -918,10 +919,6 @@
try {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> Entering function."); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pType = " + pType); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pRate = " + pRate); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pAmountA = " + pAmountA); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pAmountB = " + pAmountB); }
/* Removing extra decimals. */
@@ -929,6 +926,11 @@
pAmountA = thisObject.truncDecimals(pAmountA);
pAmountB = thisObject.truncDecimals(pAmountB);
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pType = " + pType); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pRate = " + pRate); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pAmountA = " + pAmountA); }
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] putPosition -> pAmountB = " + pAmountB); }
/* Validations that the limits are not surpassed. */
if (pType === 'buy') {
@@ -947,24 +949,6 @@
callBackFunction(err);
return;
}
let aRate = thisObject.truncDecimals(pAmountA / pRate);
if (aRate !== pAmountB) {
logger.write(MODULE_NAME, "[ERROR] putPosition -> Input Validations -> pAmountA / pRate !== pAmountB.");
logger.write(MODULE_NAME, "[ERROR] putPosition -> Input Validations -> pAmountA = " + pAmountA);
logger.write(MODULE_NAME, "[ERROR] putPosition -> Input Validations -> pAmountB = " + pAmountB);
logger.write(MODULE_NAME, "[ERROR] putPosition -> Input Validations -> pRate = " + pRate);
let err = {
result: global.DEFAULT_FAIL_RESPONSE.result,
message: 'pAmountB * pRate !== pAmountA'
};
callBackFunction(err);
return;
}
}
if (pType === 'sell') {
@@ -983,24 +967,6 @@
callBackFunction(err);
return;
}
let bRate = thisObject.truncDecimals(pAmountB * pRate);
if (bRate !== pAmountA) {
logger.write(MODULE_NAME, "[ERROR] putPosition -> Input Validations -> pAmountB * pRate !== pAmountA.");
logger.write(MODULE_NAME, "[ERROR] putPosition -> Input Validations -> pAmountA = " + pAmountA);
logger.write(MODULE_NAME, "[ERROR] putPosition -> Input Validations -> pAmountB = " + pAmountB);
logger.write(MODULE_NAME, "[ERROR] putPosition -> Input Validations -> pRate = " + pRate);
let err = {
result: global.DEFAULT_FAIL_RESPONSE.result,
message: 'pAmountB * pRate !== pAmountA'
};
callBackFunction(err);
return;
}
}
/* All validations passed, we proceed. */
@@ -1017,8 +983,8 @@
if (pRate !== marketRate) {
logger.write(MODULE_NAME, "[ERROR] putPosition -> Input Validations -> putPosition Rate can not be different to marketRate while in Backtesting Mode. ");
onResponse(global.DEFAULT_FAIL_RESPONSE, positionId);
logger.write(MODULE_NAME, "[WARNING] putPosition -> Input Validations -> putPosition Rate can is different to marketRate while in Backtesting Mode. ");
//onResponse(global.DEFAULT_FAIL_RESPONSE, positionId);
}
let positionId = Math.trunc(Math.random(1) * 1000000);
@@ -1393,45 +1359,8 @@
}
function sendEmail(pTitle, pBody, pTo) {
try {
/**
Email configuration is not available when running the bot on the browser.
*/
if (global.CURRENT_EXECUTION_AT === "Browser") {
logger.write(MODULE_NAME, "[WARN] sendEmail -> Send emails is disabled from the browser.");
return;
}
let emailList = pTo; //TODO Pending to add spam controller
let runIndex = context.statusReport.runs.length - 1;
let transporter = nodemailer.createTransport({
service: global.EMAIL_CONFIG.service,
auth: {
user: global.EMAIL_CONFIG.user,
pass: global.EMAIL_CONFIG.pass
}
});
let mailOptions = {
from: global.EMAIL_CONFIG.from,
bcc: emailList,
subject: bot.startMode + "." + runIndex + ' - ' + pTitle,
text: pBody
};
transporter.sendMail(mailOptions, function (error, info) {
if (error) {
logger.write(MODULE_NAME, "[ERROR] sendEmail -> err = " + error);
} else {
logger.write(MODULE_NAME, "[INFO] sendEmail -> Email sent = " + info.response);
}
});
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] sendEmail -> err = " + err.message);
}
logger.write(MODULE_NAME, "[WARN] sendEmail -> Send emails is currently disabled.");
return;
}
function truncDecimals(pFloatValue, pDecimals) {
+1 -1
View File
@@ -34,7 +34,7 @@ This Code of Conduct applies both within project spaces and in public spaces whe
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at feedback at advancedalgos dot org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team using the online form in the contacts page of the superalgos.org website. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
+17 -17
View File
@@ -2,44 +2,44 @@
We are thrilled you are interested in contributing to this repository. Your help may be essential to the project's success and we want you in!
Advanced Algos LTD is a startup, currently at a very early stage. Although this repository is not open source software yet, we do welcome contributions from the community.
Superalgos is a collective project, currently at a very early stage. Although this repository is not open source software yet, we do welcome contributions from the community.
Contributions are deemed _voluntary work_. There might be incentives in place for certain kinds of contributions. Contact us for more information in this regards.
Contributions are deemed _voluntary work_. There might be incentives in place for certain kinds of contributions. Contact us for more information in this regard.
In any case, contributors agree to provide an express grant of patent rights for their contributions. Submitting Pull Requests to this repository represents an express agreement with the terms of our Balanced Contributor Intellectual Property Agreement. This agreement is a direct implementation of GitHub's [Balanced Employee Intellectual Property Agreement 1.0.1](https://github.com/github/balanced-employee-ip-agreement/blob/master/Balanced_Employee_IP_Agreement.md).
# Balanced Contributor Intellectual Property Agreement 1.0.1
This BALANCED CONTRIBUTOR INTELLECTUAL PROPERTY AGREEMENT is between person or team submitting Pull Requests to this repository and Advanced Algos LTD ("Company").
This BALANCED CONTRIBUTOR INTELLECTUAL PROPERTY AGREEMENT is between person or team submitting Pull Requests to this repository and Superalgos.org ("Project").
**What is this?** This is the Company's Intellectual Property Agreement ("Agreement"). If you've worked in the technology space before, there's a good chance that you've run across one or more of these in the past. This document is the official, entire and exclusive agreement on what intellectual property ("IP") is yours, and what belongs to the Company.
**What is this?** This is the Project's Intellectual Property Agreement ("Agreement"). If you've worked in the technology space before, there's a good chance that you've run across one or more of these in the past. This document is the official, entire and exclusive agreement on what intellectual property ("IP") is yours, and what belongs to the Project.
**Why is this?** The Company needs to be clear on what IP it owns and has rights to. Its customers, contributors, and investors depend on the Company having the legal rights to the products and services it is providing so that the Company can continue operating and doing business.
**Why is this?** The Project needs to be clear on what IP it owns and has rights to. Its customers, contributors, and investors depend on the Project having the legal rights to the products and services it is providing so that the Project can continue operating and doing business.
The Company also believes that it's important to be clear on what it doesn't own. The Company doesn't want you looking over your shoulder every time you work on something personal or worrying that the Company will someday seize your open source non-lethal mousetrap simulation software. In other words, the Company isn't interested in appropriating your personal projects.
The Project also believes that it's important to be clear on what it doesn't own. The Project doesn't want you looking over your shoulder every time you work on something personal or worrying that the Project will someday seize your open source non-lethal mousetrap simulation software. In other words, the Project isn't interested in appropriating your personal projects.
**Read this.** Please read this document and be sure you understand it before you submit any Pull Requests. Due to legal risk and corporate obligations, the Company cannot, by and large, negotiate its terms. If you feel you have a particular circumstance that keeps you from signing, please let the Company's legal department ("Legal") know. And, of course, you're always free and encouraged to get your own legal counsel to explain anything you're not clear on.
**Read this.** Please read this document and be sure you understand it before you submit any Pull Requests. Due to legal risk and corporate obligations, the Project cannot, by and large, negotiate its terms. If you feel you have a particular circumstance that keeps you from signing, please let the Project's legal department ("Legal") know. And, of course, you're always free and encouraged to get your own legal counsel to explain anything you're not clear on.
Cool? Then, by submitting your first Pull Request, and as a condition of your contribution, you agree to the following:
1. **What the Company owns.** The Company owns any IP ("Company IP") that you create, or help create _as its contributor_, but only if it meets one or more of these additional conditions: The IP was (i) related to an existing or prospective Company product or service at the time you developed, invented, or created it, (ii) developed for use by the Company, or (iii) developed or promoted with existing Company IP or with the Company's endorsement. You hereby grant and assign, and will grant and assign, to the Company all rights and interests in all Company IP.
1. **What the Project owns.** The Project owns any IP ("Project IP") that you create, or help create _as its contributor_, but only if it meets one or more of these additional conditions: The IP was (i) related to an existing or prospective Project product or service at the time you developed, invented, or created it, (ii) developed for use by the Project, or (iii) developed or promoted with existing Project IP or with the Project's endorsement. You hereby grant and assign, and will grant and assign, to the Project all rights and interests in all Project IP.
"Company IP" includes concepts, designs, developments, discoveries, ideas, improvements, inventions, trade secrets, trademarks, and works of authorship.
"Project IP" includes concepts, designs, developments, discoveries, ideas, improvements, inventions, trade secrets, trademarks, and works of authorship.
2. **What the Company doesn't own.** If you create IP that doesn't fit into one of the categories listed above, the Company doesn't own it. In other words, the Company doesn't own concepts, designs, developments, discoveries, ideas, improvements, inventions, trade secrets, trademarks, or works of authorship that you develop, invent, or create that do not meet any of the conditions in Section 1.
2. **What the Project doesn't own.** If you create IP that doesn't fit into one of the categories listed above, the Project doesn't own it. In other words, the Project doesn't own concepts, designs, developments, discoveries, ideas, improvements, inventions, trade secrets, trademarks, or works of authorship that you develop, invent, or create that do not meet any of the conditions in Section 1.
3. **Contribution of your IP to Company projects.** If you include your own IP – such as IP you created prior to working for the Company – into a Company product or service, it's still yours, of course, but you grant the Company a non-exclusive, irrevocable, fully paid-up, royalty-free, perpetual, sublicensable, transferable, worldwide license to use it without restriction in any way or implementation, in modified form, or as is, by itself, or incorporated into another product or service ("License"). If you include your name in any project over which the Company would have rights under this Agreement, such as in a copyright notice or a comment in code or documentation, then the License covers the rights associated with that use of your name as well.
3. **Contribution of your IP to Project projects.** If you include your own IP – such as IP you created prior to working for the Project – into a Project product or service, it's still yours, of course, but you grant the Project a non-exclusive, irrevocable, fully paid-up, royalty-free, perpetual, sublicensable, transferable, worldwide license to use it without restriction in any way or implementation, in modified form, or as is, by itself, or incorporated into another product or service ("License"). If you include your name in any project over which the Project would have rights under this Agreement, such as in a copyright notice or a comment in code or documentation, then the License covers the rights associated with that use of your name as well.
4. **Your contributions to non-Company projects.** The Company recognizes that you may be engaged in work that requires you to submit IP to entities other than the Company, such as open source projects used by the Company. Please make sure that Legal is aware of what you're working on so that Legal can help with any licensing issues. If any project asks you to sign a contribution agreement, you should check with Legal before doing so. These agreements may be legally binding on the Company and so should be run through Legal first.
4. **Your contributions to non-Project projects.** The Project recognizes that you may be engaged in work that requires you to submit IP to entities other than the Project, such as open source projects used by the Project. Please make sure that Legal is aware of what you're working on so that Legal can help with any licensing issues. If any project asks you to sign a contribution agreement, you should check with Legal before doing so. These agreements may be legally binding on the Project and so should be run through Legal first.
5. **Voluntary Works** All Company IP that you are involved with or create as part of your work for the Company is voluntary work which does not require compensation. There might be incentives in place for certain kinds of contributions. Feel free to contact the Company to learn more.
5. **Voluntary Works** All Project IP that you are involved with or create as part of your work for the Project is voluntary work which does not require compensation. There might be incentives in place for certain kinds of contributions. Feel free to contact the Project to learn more.
6. **No conflicts.** You agree that you don't have any outstanding agreements or obligations that conflict with those in this Agreement, and that you won't enter into conflicting agreements in the future.
7. **IP protection.** The Company might someday need to show the work that went into the development of IP that it uses or has used, or to make government filings to establish that it owns the IP or has rights over it. To help in those situations, you agree not to destroy any records you maintain relating to the development of any Company IP or IP under License (together, "All IP"), and, if the Company asks, to provide those records to the Company. You agree to help the Company secure and defend its rights in All IP. For your help the Company will compensate you at a reasonable rate. If the Company is unable to secure your help, you authorize the Company to act on your behalf (as your agent and attorney-in-fact) in securing all rights related to All IP.
7. **IP protection.** The Project might someday need to show the work that went into the development of IP that it uses or has used, or to make government filings to establish that it owns the IP or has rights over it. To help in those situations, you agree not to destroy any records you maintain relating to the development of any Project IP or IP under License (together, "All IP"), and, if the Project asks, to provide those records to the Project. You agree to help the Project secure and defend its rights in All IP. For your help the Project will compensate you at a reasonable rate. If the Project is unable to secure your help, you authorize the Project to act on your behalf (as your agent and attorney-in-fact) in securing all rights related to All IP.
8. **Confidentiality.** As an contributor or contractor of the Company, you will have access to sensitive confidential information that is important to the Company's business. You are responsible for keeping this information confidential, including after you end your work for the Company.
8. **Confidentiality.** As an contributor or contractor of the Project, you will have access to sensitive confidential information that is important to the Project's business. You are responsible for keeping this information confidential, including after you end your work for the Project.
"Confidential Information" includes non-public technical details about our products or services, financial information, business strategies and forecasts, customer data, or any other information, data or know-how that is valuable to the Company because it is not publicly known.
"Confidential Information" includes non-public technical details about our products or services, financial information, business strategies and forecasts, customer data, or any other information, data or know-how that is valuable to the Project because it is not publicly known.
The Company's Confidential Information is sensitive and we expect that you'll treat it as such. You agree to only use the Company's Confidential Information for the purpose of performing your contribution and for the benefit of the Company. You will do your best to keep Confidential Information secret. If you are not sure if something is Confidential Information, you should assume that it is, until you can confirm otherwise.
The Project's Confidential Information is sensitive and we expect that you'll treat it as such. You agree to only use the Project's Confidential Information for the purpose of performing your contribution and for the benefit of the Project. You will do your best to keep Confidential Information secret. If you are not sure if something is Confidential Information, you should assume that it is, until you can confirm otherwise.
View File
File renamed without changes.
+22 -1
View File
@@ -38,7 +38,28 @@
let USER_BOT_MODULE = {};
USER_BOT_MODULE.newUserBot = eval(text);
callBackFunction(global.DEFAULT_OK_RESPONSE, USER_BOT_MODULE);
/*
This following code is to load the bot code from a file on the file system.
It is useful for when you are activelly changing the code and dont wont to upload it to the storage at every run
*/
/*
let fs = require('fs');
try {
let fileName = "C:/Users/Luis/source/repos/Bots/AAMasters/AAChris-Indicator-Bot/Multi-Period-Daily/User.Bot.js";
fs.readFile(fileName, onFileRead);
function onFileRead(err, file) {
let fileString = file.toString();
USER_BOT_MODULE.newUserBot = eval(fileString);
callBackFunction(global.DEFAULT_OK_RESPONSE, USER_BOT_MODULE);
}
}
catch(err) {
console.log("ERROR LOADING FILE FROM FILE SYSTEM");
}
*/
callBackFunction(global.DEFAULT_OK_RESPONSE, USER_BOT_MODULE); // Coment this when loading from file system.
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] downloadBot -> onFileReceived -> err.message = " + err.message);
-1
View File
@@ -169,7 +169,6 @@
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> getStatusReport -> err = " + err.message);
logger.write(MODULE_NAME, "[ERROR] initialize -> getStatusReport -> key = " + key);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
+14 -4
View File
@@ -9,6 +9,7 @@
let ownerBot; // This is the bot owner of the Data Set.
let thisObject = {
config: undefined,
dataSets: new Map(),
initialize: initialize,
keys: []
@@ -23,6 +24,15 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); }
thisObject.config = pDataDependenciesConfig;
if (thisObject.config === undefined) {
// We allow old indicators not to declare their data dependencies.
callBackFunction(global.DEFAULT_OK_RESPONSE);
return;
}
/*
For each dependency declared at the bot config, we will initialize a DataSet as part of this initialization process.
@@ -31,11 +41,11 @@
let alreadyCalledBack = false;
let addCount = 0;
for (let i = 0; i < pDataDependenciesConfig.length; i++) {
for (let i = 0; i < thisObject.config.length; i++) {
let dataSetModule = DATA_SET.newDataSet(BOT, logger, BLOB_STORAGE, UTILITIES);
dataSetModule.initialize(pDataDependenciesConfig[i], onInitilized);
dataSetModule.initialize(thisObject.config[i], onInitilized);
function onInitilized(err) {
@@ -58,14 +68,14 @@
let key;
key = pDataDependenciesConfig[i].devTeam + "-" + pDataDependenciesConfig[i].bot + "-" + pDataDependenciesConfig[i].product + "-" + pDataDependenciesConfig[i].dataSet + "-" + pDataDependenciesConfig[i].dataSetVersion;
key = thisObject.config[i].devTeam + "-" + thisObject.config[i].bot + "-" + thisObject.config[i].product + "-" + thisObject.config[i].dataSet + "-" + thisObject.config[i].dataSetVersion;
thisObject.keys.push(key);
thisObject.dataSets.set(key, dataSetModule);
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> addDataSet -> DataSet added to Map. -> key = " + key); }
if (addCount === pDataDependenciesConfig.length) {
if (addCount === thisObject.config.length) {
if (alreadyCalledBack === false) {
callBackFunction(global.DEFAULT_OK_RESPONSE);
return;
-1
View File
@@ -5,7 +5,6 @@
let bot = BOT;
let thisObject = {
file: undefined, // Here we have the JSON object representing the file content.
initialize: initialize,
getTextFile: getTextFile,
createTextFile: createTextFile
+3 -18
View File
@@ -60,13 +60,6 @@
internalLoopCounter++;
if (global.CURRENT_EXECUTION_AT === "Browser") {
//console.log("[INFO] DebugLog -> persist -> We do not persist logs while running at the Browser");
return;
}
let contentToPersist = accumulatedLog;
accumulatedLog = "[";
@@ -149,28 +142,20 @@
if (global.CURRENT_EXECUTION_AT === "IDE") {
console.log("AACloud" + spacePad(pModule, 50) + " : " + pMessage);
console.log("CloneExecutor" + spacePad(pModule, 50) + " : " + pMessage);
}
if (disableLogging === true) { return; }
if (global.CURRENT_EXECUTION_AT === "Browser") {
/* Only at the browser we send the messages to the console. At the Cloud it does not make sense. */
console.log("AACloud" + spacePad(pModule, 50) + " : " + pMessage);
return;
}
if (global.CURRENT_EXECUTION_AT === "Cloud") {
if (global.CURRENT_EXECUTION_AT === "Node") {
/* Only ERRORs go to the cloud console. */
if (pMessage.indexOf("[ERROR]") >= 0) {
let now = new Date;
console.log("Loop." + pad(thisObject.bot.loopCounter, 8) + " " + now.toUTCString() + " AACloud " + spacePad(pModule, 20) + " : " + pMessage);
console.log("Loop." + pad(thisObject.bot.loopCounter, 8) + " " + now.toUTCString() + " CloneExecutor " + spacePad(pModule, 20) + " : " + pMessage);
}
}
@@ -1,16 +1,13 @@
exports.newExchangeAPI = function newExchangeAPI(bot, logger) {
exports.newExchangeAPI = function newExchangeAPI(logger, authToken) {
/*
This module allows trading bots to connect to the exchange and do trading operations on it. So far it can only work with Poloniex.
*/
const _ = require('lodash');
const isValidOrder = require('./exchangeUtils').isValidOrder;
const graphqlClient = require('graphql-client')
const request = require('request')
const authOptions = require('./Auth0')
const _ = require('lodash')
const isValidOrder = require('./exchangeUtils').isValidOrder
const axios = require('axios')
let MODULE_NAME = "Exchange API";
let thisObject = {
@@ -29,74 +26,73 @@
return thisObject;
function initialize(callBackFunction) {
async function initialize(callBackFunction) {
try {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); }
// TODO integrate with financial beings module to get the exchange
let botExchange = 'Poloniex';
let exchange = botExchange.toLowerCase() + 'Client.js';
let api = require('./Wrappers/' + exchange);
request(authOptions, onTokenResponse);
let api = require('./wrappers/' + exchange);
function onTokenResponse(error, response, body) {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] onTokenResponse -> Entering function."); }
let accessToken
let keyId
let cloneId
if (global.CURRENT_EXECUTION_AT === "Node") {
keyId = process.env.KEY_ID
cloneId = process.env.CLONE_ID
if (error) {
logger.write(MODULE_NAME, "[ERROR] onTokenResponse -> err = " + error.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
} else {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] onTokenResponse -> Token Received."); }
let response = JSON.parse(body)
let authToken = response.access_token
let keyVaultAPI = createKeyVaultAPIClient(authToken)
apiClient = api.newAPIClient(keyVaultAPI, logger);
let auth = require('../utils/auth')
let authTokenCloud = await auth.authenticate()
accessToken = 'Bearer ' + authTokenCloud
}
let keyVaultAPI = createKeyVaultAPIClient(accessToken, keyId, cloneId)
apiClient = api.newAPIClient(keyVaultAPI, logger);
callBackFunction(global.DEFAULT_OK_RESPONSE);
callBackFunction(global.DEFAULT_OK_RESPONSE);
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.message);
logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.stack);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function createKeyVaultAPIClient(authToken) {
function createKeyVaultAPIClient(accessToken, keyId, cloneId) {
if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createKeyVaultAPIClient -> Entering function."); }
const keyVaultAPI = graphqlClient({
url: 'https://app-api.advancedalgos.net/graphql',
headers: {
Authorization: 'Bearer ' + authToken
}
});
const keyVaultAPI = {}
keyVaultAPI.signTransaction = function (transaction, next) {
let variables = {
botId: bot.codeName,
transaction: transaction
}
axios({
url: global.GATEWAY_ENDPOINT,
method: 'post',
data: {
query: `
mutation keyVault_SignTransaction($transaction: String!, $keyId: String, $cloneId: String){
keyVault_SignTransaction(transaction: $transaction, keyId: $keyId, cloneId: $cloneId){
key,
signature,
date
}
}
`,
variables: {
transaction: transaction,
keyId: keyId,
cloneId: cloneId
}
},
headers: {
authorization: accessToken
}
keyVaultAPI.query(`
mutation($botId: String, $transaction: String!){
keyVault_SignTransaction(botId: $botId, transaction: $transaction){
key,
signature,
date
}
}`, variables, function (req, res) {
if (res.status === 401) {
next(undefined, 'Error from graphql: Not authorized');
}
}).then(res => {
if (res.errors) {
next(undefined, 'Error from graphql: ' + res.errors);
} else {
let signature = {
Key: res.data.keyVault_SignTransaction.key,
Sign: res.data.keyVault_SignTransaction.signature
Key: res.data.data.keyVault_SignTransaction.key,
Sign: res.data.data.keyVault_SignTransaction.signature
}
next(signature)
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -6,7 +6,7 @@
*/
const FULL_LOG = true;
const LOG_FILE_CONTENT = true;
const LOG_FILE_CONTENT = false;
const MODULE_NAME = "poloniexClient";
const retry = require('../exchangeUtils').retry;
@@ -300,7 +300,7 @@
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] analizeResponse -> exchangeErr = " + stringExchangeErr); }
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] analizeResponse -> exchangeResponse = " + stringExchangeResponse); }
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] analizeResponse -> exchangeResponse = " + stringExchangeResponse); }
if (exchangeErr) {
error = global.DEFAULT_FAIL_RESPONSE;
+16 -64
View File
@@ -47,21 +47,11 @@
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
let filePath;
switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy.
case "Cloud": {
filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud.
break;
}
case "Browser": {
filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser.
break;
}
default: {
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'.");
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return; }
if (global.RUN_AS_TEAM) {
filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud.
} else {
filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser.
}
const CLOUD_REQUIRE = require(ROOT_DIR + 'CloudRequire');
@@ -80,23 +70,8 @@
USER_BOT_MODULE = pMODULE;
switch (global.CURRENT_EXECUTION_AT) {
case "Cloud": {
filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo;
break;
}
case "Browser": {
filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO;
break;
}
default: {
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'.");
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return;
}
}
filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo;
cloudRequire.downloadCommons(cloudStorage, filePath, onCommonsDownloaded);
function onCommonsDownloaded(err, pMODULE) {
@@ -154,8 +129,6 @@
return str.length < max ? pad(" " + str, max) : str;
}
console.log(new Date().toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " " + pad(pMonth, 2) + "/" + pad(pYear, 4) + " Entered into Main Loop # " + pad(Number(bot.loopCounter) + 1, 8));
/* For each loop we want to create a new log file. */
logger = DEBUG_MODULE.newDebugLog();
@@ -178,6 +151,11 @@
bot.processDatetime = new Date(); // This will be considered the process date and time, so as to have it consistenly all over the execution.
/* High level log entry */
console.log(bot.processDatetime.toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " " + pad(pMonth, 2) + "/" + pad(pYear, 4)
+ " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8));
/* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */
let userBot;
@@ -268,7 +246,7 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeExchangeAPI -> Entering function."); }
exchangeAPI = EXCHANGE_API.newExchangeAPI(bot, logger);
exchangeAPI = EXCHANGE_API.newExchangeAPI(logger);
exchangeAPI.initialize(onInizialized);
@@ -657,7 +635,7 @@
function checkLoopHealth(pLastLoop) {
if (global.CURRENT_EXECUTION_AT !== "Cloud") {
if (global.CURRENT_EXECUTION_AT !== "Node") {
return;
}
@@ -707,34 +685,8 @@
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
let filePath;
switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy.
case "Cloud": {
filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud.
break;
}
case "Browser": {
if (global.SHALL_BOT_STOP === false) {
continueCallBack();
} else {
stopCallBack();
}
return;
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> shallWeStop -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'.");
logger.write(MODULE_NAME, "[ERROR] run -> loop -> shallWeStop -> onInizialized -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT);
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return;
}
}
let filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud.
let fileName = "this.config.json";
cloudStorage.getTextFile(filePath, fileName, onFileReceived);
+352 -63
View File
@@ -9,6 +9,8 @@
let COMMONS_MODULE;
const BLOB_STORAGE = require(ROOT_DIR + 'BlobStorage');
const MULTI_PERIOD_MARKET = require(ROOT_DIR + 'MultiPeriodMarket');
const MULTI_PERIOD_DAILY = require(ROOT_DIR + 'MultiPeriodDaily');
const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog');
let logger; // We need this here in order for the loopHealth function to work and be able to rescue the loop when it gets in trouble.
@@ -48,21 +50,10 @@
let filePath;
switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy.
case "Cloud": {
filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud.
break;
}
case "Browser": {
filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser.
break;
}
default: {
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'.");
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return;
}
if (global.RUN_AS_TEAM) {
filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud.
} else {
filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser.
}
const CLOUD_REQUIRE = require(ROOT_DIR + 'CloudRequire');
@@ -81,22 +72,7 @@
USER_BOT_MODULE = pMODULE;
switch (global.CURRENT_EXECUTION_AT) {
case "Cloud": {
filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo;
break;
}
case "Browser": {
filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO;
break;
}
default: {
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'.");
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return;
}
}
filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo;
cloudRequire.downloadCommons(cloudStorage, filePath, onCommonsDownloaded);
@@ -155,8 +131,6 @@
return str.length < max ? pad(" " + str, max) : str;
}
console.log(new Date().toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " " + pad(pMonth, 2) + "/" + pad(pYear, 4) + " Entered into Main Loop # " + pad(Number(bot.loopCounter) + 1, 8 ));
/* For each loop we want to create a new log file. */
logger = DEBUG_MODULE.newDebugLog();
@@ -173,15 +147,24 @@
const UTILITIES = require(ROOT_DIR + 'CloudUtilities');
const STATUS_REPORT = require(ROOT_DIR + 'StatusReport');
const STATUS_DEPENDENCIES = require(ROOT_DIR + 'StatusDependencies');
const DATA_DEPENDENCIES = require(ROOT_DIR + 'DataDependencies');
const DATA_SET = require(ROOT_DIR + 'DataSet');
/* We define the datetime for the process that we are running now. This will be the official processing time for both the infraestructure and the bot. */
bot.processDatetime = new Date(); // This will be considered the process date and time, so as to have it consistenly all over the execution.
/* High level log entry */
console.log(bot.processDatetime.toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.process, 30) + " " + pad(pMonth, 2) + "/" + pad(pYear, 4)
+ " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8));
/* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */
let userBot;
let processFramework;
let statusDependencies;
let dataDependencies;
let nextWaitTime;
@@ -206,7 +189,7 @@
switch (err.result) {
case global.DEFAULT_OK_RESPONSE.result: {
logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeStatusDependencies -> onInizialized -> Execution finished well.");
initializeUserBot();
initializeDataDependencies();
return;
}
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
@@ -262,6 +245,109 @@
}
}
function initializeDataDependencies() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeDataDependencies -> Entering function."); }
dataDependencies = DATA_DEPENDENCIES.newDataDependencies(bot, logger, DATA_SET, BLOB_STORAGE, UTILITIES);
dataDependencies.initialize(processConfig.dataDependencies, onInizialized);
function onInizialized(err) {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeDataDependencies -> onInizialized -> Entering function."); }
switch (err.result) {
case global.DEFAULT_OK_RESPONSE.result: {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeDataDependencies -> onInizialized -> Execution finished well."); }
/* If the process is configured to run inside a framework, we continue there, otherwise we run the bot directly. */
if (processConfig.framework === undefined) {
initializeUserBot();
return;
}
switch (processConfig.framework.name) {
case 'Multi-Period-Market': {
processFramework = MULTI_PERIOD_MARKET.newMultiPeriodMarket(bot, logger, COMMONS_MODULE, UTILITIES, BLOB_STORAGE, USER_BOT_MODULE, COMMONS_MODULE);
intitializeProcessFramework();
break;
}
case 'Multi-Period-Daily': {
processFramework = MULTI_PERIOD_DAILY.newMultiPeriodDaily(bot, logger, COMMONS_MODULE, UTILITIES, BLOB_STORAGE, USER_BOT_MODULE, COMMONS_MODULE);
intitializeProcessFramework();
break;
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Process Framework not Supported.");
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Process Framework Name = " + processConfig.framework.name);
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
callBackFunction(err);
return;
}
}
return;
}
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Retry Later. Requesting Execution Retry.");
nextWaitTime = 'Retry';
loopControl(nextWaitTime);
return;
}
case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Operation Failed. Aborting the process.");
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
callBackFunction(err);
return;
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result);
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> Unhandled err.result received. -> err.message = " + err.message);
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return;
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> onInizialized -> err = " + err.message);
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
callBackFunction(err);
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> initializeDataDependencies -> err = " + err.message);
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
callBackFunction(err);
}
}
function initializeUserBot() {
try {
@@ -493,6 +579,235 @@
}
}
function intitializeProcessFramework() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> intitializeProcessFramework -> Entering function."); }
processFramework.initialize(processConfig, statusDependencies, dataDependencies, onInizialized, dataDependencies);
function onInizialized(err) {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> intitializeProcessFramework -> onInizialized -> Entering function."); }
switch (err.result) {
case global.DEFAULT_OK_RESPONSE.result: {
logger.write(MODULE_NAME, "[INFO] run -> loop -> intitializeProcessFramework -> onInizialized -> Execution finished well.");
startProcessFramework();
return;
}
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Retry Later. Requesting Execution Retry.");
nextWaitTime = 'Retry';
loopControl(nextWaitTime);
return;
}
case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Operation Failed. Aborting the process.");
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
callBackFunction(err);
return;
}
case global.CUSTOM_OK_RESPONSE.result: {
switch (err.message) {
case "Too far in the future.": {
logger.write(MODULE_NAME, "[WARN] run -> loop -> intitializeProcessFramework -> onInizialized > Too far in the future. This Loop will enter in coma.");
nextWaitTime = 'Coma';
loopControl(nextWaitTime);
return;
}
case "Not needed now, but soon.": {
logger.write(MODULE_NAME, "[WARN] run -> loop -> intitializeProcessFramework -> onInizialized > Not needed now, but soon. This Loop will continue with Normal wait time.");
nextWaitTime = 'Normal';
loopControl(nextWaitTime);
return;
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized > Unhandled custom response received. -> err.message = " + err.message);
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
callBackFunction(err);
return;
}
}
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Unhandled err.result received. -> err.result = " + err.result);
logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> Unhandled err.result received. -> err.message = " + err.message);
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return;
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> onInizialized -> err = " + err.message);
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
callBackFunction(err);
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> intitializeProcessFramework -> err = " + err.message);
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
callBackFunction(err);
}
}
function startProcessFramework() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> startProcessFramework -> Entering function."); }
processFramework.start(onFinished);
function onFinished(err) {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> startProcessFramework -> onFinished -> Entering function."); }
switch (err.result) {
case global.DEFAULT_OK_RESPONSE.result: {
logger.write(MODULE_NAME, "[INFO] run -> loop -> startProcessFramework -> onFinished -> Execution finished well.");
nextWaitTime = 'Normal';
loopControl(nextWaitTime);
return;
}
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Retry Later. Requesting Execution Retry.");
nextWaitTime = 'Retry';
loopControl(nextWaitTime);
return;
}
case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Operation Failed. Aborting the process.");
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
callBackFunction(err);
return;
}
case global.CUSTOM_OK_RESPONSE.result: {
switch (err.message) {
case "Dependency does not exist.": {
logger.write(MODULE_NAME, "[WARN] run -> loop -> startProcessFramework -> onFinished -> Dependency does not exist. This Loop will go to sleep.");
nextWaitTime = 'Sleep';
loopControl(nextWaitTime);
return;
}
case "Dependency not ready.": {
logger.write(MODULE_NAME, "[WARN] run -> loop -> startProcessFramework -> onFinished -> Dependency not ready. This Loop will go to sleep.");
nextWaitTime = 'Sleep';
loopControl(nextWaitTime);
return;
}
case "Month before it is needed.": {
logger.write(MODULE_NAME, "[WARN] run -> loop -> startProcessFramework -> onFinished -> Month before it is needed. This Loop will be terminated.");
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
callBackFunction(global.DEFAULT_OK_RESPONSE);
return;
}
case "Month fully processed.": {
logger.write(MODULE_NAME, "[WARN] run -> loop -> startProcessFramework -> onFinished -> Month fully processed. This Loop will be terminated.");
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
callBackFunction(global.DEFAULT_OK_RESPONSE);
return;
}
case "End of the month reached.": {
logger.write(MODULE_NAME, "[WARN] run -> loop -> startProcessFramework -> onFinished -> End of the month reached. This Loop will be terminated.");
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
callBackFunction(global.DEFAULT_OK_RESPONSE);
return;
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Unhandled custom response received. -> err.message = " + err.message);
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
callBackFunction(err);
return;
}
}
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Unhandled err.result received. -> err.result = " + err.result);
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> Unhandled err.result received. -> err.message = " + err.message);
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return;
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> onFinished -> err = " + err.message);
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
callBackFunction(err);
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> startProcessFramework -> err = " + err.message);
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
callBackFunction(err);
}
}
function loopControl(nextWaitTime) {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Entering function."); }
@@ -553,7 +868,7 @@
function checkLoopHealth(pLastLoop) {
if (global.CURRENT_EXECUTION_AT !== "Cloud") {
if (global.CURRENT_EXECUTION_AT !== "Node") {
return;
}
@@ -603,34 +918,8 @@
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
let filePath;
switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy.
case "Cloud": {
filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud.
break;
}
case "Browser": {
if (global.SHALL_BOT_STOP === false) {
continueCallBack();
} else {
stopCallBack();
}
return;
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> shallWeStop -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'.");
logger.write(MODULE_NAME, "[ERROR] run -> loop -> shallWeStop -> onInizialized -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT);
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return;
}
}
let filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud.
let fileName = "this.config.json";
cloudStorage.getTextFile(filePath, fileName, onFileReceived);
@@ -0,0 +1,55 @@
const axios = require('axios')
const auth = require('../utils/auth')
exports.updateExecutionResults = async function (summaryDate, buyAverage, sellAverage,
marketRate, combinedProfitsA, combinedProfitsB) {
try {
const accessToken = await auth.authenticate()
const operationsResponse = await axios({
url: process.env.GATEWAY_ENDPOINT,
method: 'post',
data: {
query: `
mutation($id: ID!, $summaryDate: Int!, $buyAverage: Float!, $sellAverage: Float!,
$marketRate: Float!, $combinedProfitsA: Float!, $combinedProfitsB: Float!,
$assetA: String!, $assetB: String!){
operations_UpdateExecutionSummary(
id: $id,
summaryDate: $summaryDate,
buyAverage: $buyAverage,
sellAverage: $sellAverage,
marketRate: $marketRate,
combinedProfitsA: $combinedProfitsA,
combinedProfitsB: $combinedProfitsB,
assetA: $assetA,
assetB: $assetB
)
}
`,
variables: {
id: process.env.CLONE_ID,
summaryDate: summaryDate,
buyAverage: buyAverage,
sellAverage: sellAverage,
marketRate: marketRate,
combinedProfitsA: combinedProfitsA,
combinedProfitsB: combinedProfitsB,
assetA: global.MARKET.assetA,
assetB: global.MARKET.assetB
},
},
headers: {
authorization: 'Bearer ' + accessToken
}
})
if (operationsResponse.data.errors)
throw new Error(operationsResponse.data.errors[0].message)
} catch (error) {
throw new Error('There has been an error updating the execution on the clone: ' + error)
}
}
+14 -17
View File
@@ -1,23 +1,22 @@
COPYRIGHT NOTICE
© Copyright 2018 Advanced Algos LTD.
© Copyright 2018 Superalgos.org
LICENSE NOTICE
Advanced Algos LTD. is a startup, currently at a very early stage. Because certain aspects of
the business are still not clearly defined, we have chosen to --temporarily-- grant a
restrictive license for the use of this repository, until those business aspects are clarified
and a proper open source license can be granted.
Superalgos is a collaborative project currently at a very early stage. Because certain aspects of
the project are still not clearly defined, we have chosen to --temporarily-- grant a restrictive
license for the use of this repository, until those aspects are clarified and a proper open source
license can be granted.
Advanced Algos LTD. is publishing the code of this software for several reasons. However,
it shall not be considered free software yet. Advanced Algos LTD. is a for-profit company
in the crypto space and this module is still proprietary software.
Superalgos.org is publishing the code of this software for several reasons. However, it shall not be considered free software yet. Superalgos is a collaborative project in the crypto space and this
software is still proprietary software.
The reasons for opening up the code of this module at this stage are the following:
The reasons for opening up the code of this software at this stage are the following:
* We believe that transparency is paramount to achieving our goals, so we want everyone
to be able to understand what this module does and how. Opening up the code of this module
* We believe that transparency is paramount to achieving our goals, so we want everyone to
be able to understand what this software does and how. Opening up the code of this software
allows anyone to take a close look.
* We welcome contributions from the community. Contributions are regarded as voluntary work.
@@ -27,16 +26,14 @@ The reasons for opening up the code of this module at this stage are the followi
LICENSE WORDING
Advanced Algos LTD. grants a limited license for the following uses:
Superalgos.org grants a limited license for the following uses:
1. CODE REVIEW AND AUDITS. You are granted permission to clone this repository to analyze,
review or audit the code.
2. COLLABORATING WITH ADVANCED ALGOS LTD. You are granted permission to fork this repository
2. COLLABORATING WITH Superalgos.org. You are granted permission to fork this repository
with the sole purpose of correcting bugs and developing functionality in agreement with
Advanced Algos LTD. By contributing to this repository you explicitely agree to the terms
Superalgos.org. By contributing to this repository you explicitely agree to the terms
detailed in CONTRIBUTING.MD.
PLEASE SEE CONTRIBUTING.MD FOR MORE DETAILS ON THE IMPLICATIONS SURROUNDING YOUR CONTRIBUTIONS TO THIS REPOSITORY.
PLEASE SEE CONTRIBUTING.MD FOR MORE DETAILS ON THE IMPLICATIONS SURROUNDING YOUR CONTRIBUTIONS TO THIS REPOSITORY.
+761
View File
@@ -0,0 +1,761 @@
exports.newMultiPeriodDaily = function newMultiPeriodDaily(bot, logger, COMMONS, UTILITIES, BLOB_STORAGE, USER_BOT_MODULE, COMMONS_MODULE) {
const FULL_LOG = true;
const LOG_FILE_CONTENT = false;
const MODULE_NAME = "Multi Period Daily";
const EXCHANGE_NAME = "Poloniex";
const commons = COMMONS.newCommons(bot, logger, UTILITIES);
const GMT_SECONDS = ':00.000 GMT+0000';
const ONE_DAY_IN_MILISECONDS = 24 * 60 * 60 * 1000;
thisObject = {
initialize: initialize,
start: start
};
let utilities = UTILITIES.newCloudUtilities(bot, logger);
let statusDependencies;
let dataDependencies;
let storages = [];
let dataFiles = [];
let usertBot;
let currentBotStorage = BLOB_STORAGE.newBlobStorage(bot, logger);
let processConfig;
return thisObject;
function initialize(pProcessConfig, pStatusDependencies, pDataDependencies, callBackFunction) {
try {
logger.fileName = MODULE_NAME;
logger.initialize();
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); }
statusDependencies = pStatusDependencies;
dataDependencies = pDataDependencies;
processConfig = pProcessConfig;
for (let i = 0; i < dataDependencies.config.length; i++) {
let key;
let storage;
let dependency = dataDependencies.config[i];
key = dependency.devTeam + "-" +
dependency.bot + "-" +
dependency.product + "-" +
dependency.dataSet + "-" +
dependency.dataSetVersion
storage = dataDependencies.dataSets.get(key);
storages.push(storage);
}
currentBotStorage.initialize(bot.devTeam, onStorageInizialized);
function onStorageInizialized(err) {
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
usertBot = USER_BOT_MODULE.newUserBot(bot, logger, COMMONS_MODULE, UTILITIES, BLOB_STORAGE);
usertBot.initialize(dataDependencies, callBackFunction);
} else {
logger.write(MODULE_NAME, "[ERROR] initialize -> onStorageInizialized -> err = " + err.message);
callBackFunction(err);
}
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function start(callBackFunction) {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); }
let market = global.MARKET;
/* Context Variables */
let contextVariables = {
lastFile: undefined, // Datetime of the last file files sucessfully produced by this process.
dateBeginOfMarket: undefined, // Datetime of the first trade file in the whole market history.
dateEndOfMarket: undefined // Datetime of the last file available to be used as an input of this process.
};
let previousDay; // Holds the date of the previous day relative to the processing date.
let currentDay; // Holds the processing date.
let interExecutionMemoryArray;
getContextVariables();
function getContextVariables() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> Entering function."); }
let thisReport;
let reportKey;
let statusReport;
if (processConfig.framework.startDate.fixedDate !== undefined) {
/* The starting date is fixed, we will start from there. */
contextVariables.dateBeginOfMarket = new Date(processConfig.framework.startDate.fixedDate);
} else {
/*
We look first for the bot who knows the begining of the marke in order to get when the market starts.
*/
let botWhoKnowsTheBeginingOfTheMarket = statusDependencies.config[processConfig.framework.startDate.takeItFromStatusDependency];
reportKey = botWhoKnowsTheBeginingOfTheMarket.devTeam + "-" + botWhoKnowsTheBeginingOfTheMarket.bot + "-" + botWhoKnowsTheBeginingOfTheMarket.process + "-" + "dataSet.V1";
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
statusReport = statusDependencies.statusReports.get(reportKey);
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
return;
}
if (statusReport.status === "Status Report is corrupt.") {
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
return;
}
thisReport = statusDependencies.statusReports.get(reportKey).file;
if (thisReport.lastFile === undefined) {
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey);
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> It is too early too run this process since the trade history of the market is not there yet.");
let customOK = {
result: global.CUSTOM_OK_RESPONSE.result,
message: "Dependency does not exist."
}
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message);
callBackFunction(customOK);
return;
}
contextVariables.dateBeginOfMarket = new Date(thisReport.lastFile.year + "-" + thisReport.lastFile.month + "-" + thisReport.lastFile.days + " " + thisReport.lastFile.hours + ":" + thisReport.lastFile.minutes + GMT_SECONDS);
}
if (processConfig.framework.endDate.fixedDate !== undefined) {
/* The ending date is fixed, we will end there. */
contextVariables.dateEndOfMarket = new Date(processConfig.framework.endDate.fixedDate);
} else {
/*
Here we get the status report from the bot who knows which is the end of the market.
*/
let botWhoKnowsTheEndOfTheMarket = statusDependencies.config[processConfig.framework.endDate.takeItFromStatusDependency];
reportKey = botWhoKnowsTheEndOfTheMarket.devTeam + "-" + botWhoKnowsTheEndOfTheMarket.bot + "-" + botWhoKnowsTheEndOfTheMarket.process + "-" + "dataSet.V1";
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
statusReport = statusDependencies.statusReports.get(reportKey);
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
return;
}
if (statusReport.status === "Status Report is corrupt.") {
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because dependecy Status Report is corrupt. ");
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
return;
}
thisReport = statusDependencies.statusReports.get(reportKey).file;
if (thisReport.lastFile === undefined) {
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Undefined Last File. -> reportKey = " + reportKey);
let customOK = {
result: global.CUSTOM_OK_RESPONSE.result,
message: "Dependency not ready."
}
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> customOK = " + customOK.message);
callBackFunction(customOK);
return;
}
contextVariables.dateEndOfMarket = new Date(thisReport.lastFile.valueOf());
}
/* Finally we get our own Status Report. */
reportKey = bot.devTeam + "-" + bot.codeName + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1";
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> reportKey = " + reportKey); }
statusReport = statusDependencies.statusReports.get(reportKey);
if (statusReport === undefined) { // This means the status report does not exist, that could happen for instance at the begining of a month.
logger.write(MODULE_NAME, "[WARN] start -> getContextVariables -> Status Report does not exist. Retrying Later. ");
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
return;
}
if (statusReport.status === "Status Report is corrupt.") {
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> Can not continue because self dependecy Status Report is corrupt. Aborting Process.");
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return;
}
thisReport = statusDependencies.statusReports.get(reportKey).file;
if (thisReport.lastFile !== undefined) {
if (bot.hasTheBotJustStarted === true && processConfig.framework.startDate.resumeExecution === "false") {
startFromBegining();
return;
}
contextVariables.lastFile = new Date(thisReport.lastFile);
interExecutionMemoryArray = thisReport.interExecutionMemoryArray;
processTimePeriods();
return;
} else {
/*
In the case when there is no status report, we assume like the last processed file is the one on the date of Begining of Market.
*/
startFromBegining();
return;
}
function startFromBegining() {
contextVariables.lastFile = new Date(contextVariables.dateBeginOfMarket.getUTCFullYear() + "-" + (contextVariables.dateBeginOfMarket.getUTCMonth() + 1) + "-" + contextVariables.dateBeginOfMarket.getUTCDate() + " " + "00:00" + GMT_SECONDS);
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> startFromBegining -> thisReport.lastFile === undefined"); }
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getContextVariables -> startFromBegining -> contextVariables.lastFile = " + contextVariables.lastFile); }
/*
The first time the process is running is the right time to create the data structure that is going to be shared across different executions.
This data structure has one object per each timePeriod.
*/
interExecutionMemoryArray = [];
for (let i = 0; i < global.dailyFilePeriods.length; i++) {
let emptyObject = {};
interExecutionMemoryArray.push(emptyObject);
}
processTimePeriods();
}
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> getContextVariables -> err = " + err.message);
if (err.message === "Cannot read property 'file' of undefined") {
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Check the bot configuration to see if all of its statusDependencies declarations are correct. ");
logger.write(MODULE_NAME, "[HINT] start -> getContextVariables -> Dependencies loaded -> keys = " + JSON.stringify(statusDependencies.keys));
}
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function processTimePeriods() {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> Entering function."); }
try {
let n;
let botNeverRan = true;
currentDay = new Date(contextVariables.lastFile.valueOf() - ONE_DAY_IN_MILISECONDS); // Go back one day to start well when we advance time at the begining of the loop.
advanceTime();
function advanceTime() {
try {
logger.newInternalLoop(bot.codeName, bot.process);
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> advanceTime -> Entering function."); }
currentDay = new Date(currentDay.valueOf() + ONE_DAY_IN_MILISECONDS);
previousDay = new Date(currentDay.valueOf() - ONE_DAY_IN_MILISECONDS);
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> advanceTime -> currentDay = " + currentDay); }
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> advanceTime -> previousDay = " + previousDay); }
/* Validation that we are not going past the head of the market. */
if (currentDay.valueOf() > contextVariables.dateEndOfMarket.valueOf()) {
const logText = "Head of the market found @ " + previousDay.getUTCFullYear() + "/" + (previousDay.getUTCMonth() + 1) + "/" + previousDay.getUTCDate() + ".";
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> advanceTime -> " + logText); }
callBackFunction(global.DEFAULT_OK_RESPONSE);
return;
}
periodsLoop();
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> advanceTime -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function periodsLoop() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoop -> Entering function."); }
/*
We will iterate through all posible periods.
*/
n = 0 // loop Variable representing each possible period as defined at the periods array.
periodsLoopBody();
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoop -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function periodsLoopBody() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> Entering function."); }
const timePeriod = global.dailyFilePeriods[n][0];
const outputPeriodLabel = global.dailyFilePeriods[n][1];
let dependencyIndex = 0;
dataFiles = [];
dependencyLoopBody();
function dependencyLoopBody() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> Entering function."); }
let dependency = dataDependencies.config[dependencyIndex];
let storage = storages[dependencyIndex];
let previousFile;
let currentFile;
if (currentDay.valueOf() > contextVariables.dateBeginOfMarket.valueOf()) {
getPreviousFile();
} else {
previousFile = [];
getCurrentFile()
}
function getPreviousFile() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> Entering function."); }
let dateForPath = previousDay.getUTCFullYear() + '/' + utilities.pad(previousDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(previousDay.getUTCDate(), 2);
let filePath = dependency.product + '/' + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath;
let fileName = market.assetA + '_' + market.assetB + ".json";
storage.getTextFile(filePath, fileName, onFileReceived, true);
function onFileReceived(err, text) {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> Entering function."); }
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> text = " + text); }
if (err.message === "File does not exist." && botNeverRan === true) {
/*
Sometimes one of the dependencies of an indicator for some reasons are not calculated from the begining of the market.
When that happens we can not find those files. What we do in this situation is to move the time fordward until we can find
all the dependencies and the first run of the bot is successful.
After that, we will not accept more missing files on any of the dependencies, and if any is missing we will abort the processing.
*/
logger.write(MODULE_NAME, "[WARN] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> Skipping day because file " + filePath + "/" + fileName + " was not found.");
advanceTime();
return;
}
if (err.result === "Fail Because" && err.message === "File does not exist.") {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> err = " + err.message);
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> filePath = " + filePath);
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> fileName = " + fileName);
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
return;
}
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> err = " + err.message);
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> filePath = " + filePath);
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> fileName = " + fileName);
callBackFunction(err);
return;
}
previousFile = JSON.parse(text);
getCurrentFile();
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> onFileReceived -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getPreviousFile -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function getCurrentFile() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> Entering function."); }
let dateForPath = currentDay.getUTCFullYear() + '/' + utilities.pad(currentDay.getUTCMonth() + 1, 2) + '/' + utilities.pad(currentDay.getUTCDate(), 2);
let filePath = dependency.product + '/' + "Multi-Period-Daily" + "/" + outputPeriodLabel + "/" + dateForPath;
let fileName = market.assetA + '_' + market.assetB + ".json";
storage.getTextFile(filePath, fileName, onFileReceived, true);
function onFileReceived(err, text) {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> Entering function."); }
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> text = " + text); }
if (err.result === "Fail Because" && err.message === "File does not exist.") {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> err = " + err.message);
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> filePath = " + filePath);
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> fileName = " + fileName);
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
return;
}
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> err = " + err.message);
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> filePath = " + filePath);
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> fileName = " + fileName);
callBackFunction(err);
return;
}
currentFile = JSON.parse(text);
let dataFile = previousFile.concat(currentFile);
dataFiles.push(dataFile);
dependencyControlLoop();
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> onFileReceived -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getCurrentFile -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoop -> dependencyLoopBody -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function dependencyControlLoop() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> dependencyControlLoop -> Entering function."); }
dependencyIndex++;
if (dependencyIndex < dataDependencies.config.length) {
dependencyLoopBody();
} else {
callTheBot();
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> dependencyControlLoop -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function callTheBot() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> Entering function."); }
const timePeriod = global.dailyFilePeriods[n][0];
const outputPeriodLabel = global.dailyFilePeriods[n][1];
usertBot.start(
dataFiles,
timePeriod,
outputPeriodLabel,
currentDay,
contextVariables.dateBeginOfMarket,
contextVariables.dateEndOfMarket,
interExecutionMemoryArray[n],
onBotFinished);
function onBotFinished(err) {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> onBotFinished -> Entering function."); }
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
callBackFunction(err);
return;
}
botNeverRan = false;
periodsControlLoop();
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> onBotFinished -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function periodsControlLoop() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsControlLoop -> Entering function."); }
n++;
if (n < global.dailyFilePeriods.length) {
periodsLoopBody();
} else {
n = 0;
writeDataRanges(onWritten);
function onWritten(err) {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> controlLoop -> onWritten -> Entering function."); }
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> controlLoop -> onWritten -> err = " + err.message);
callBackFunction(err);
return;
}
writeStatusReport(currentDay, advanceTime);
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> controlLoop -> onWritten -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsControlLoop -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function writeDataRanges(callBack) {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRanges -> Entering function."); }
let productIndex = 0;
productLoopBody();
function productLoopBody() {
let folderName = bot.products[productIndex].codeName;
writeDataRange(contextVariables.dateBeginOfMarket, currentDay, folderName, controlLoop);
}
function controlLoop() {
productIndex++;
if (productIndex < bot.products.length) {
productLoopBody();
} else {
callBack(global.DEFAULT_OK_RESPONSE);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> writeDataRanges -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
function writeDataRange(pBegin, pEnd, pProductFolder, callBack) {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> Entering function."); }
let dataRange = {
begin: pBegin.valueOf(),
end: pEnd.valueOf()
};
let fileContent = JSON.stringify(dataRange);
let fileName = 'Data.Range.' + market.assetA + '_' + market.assetB + '.json';
let filePath = bot.filePathRoot + "/Output/" + pProductFolder + "/" + bot.process;
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> fileName = " + fileName); }
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> filePath = " + filePath); }
currentBotStorage.createTextFile(filePath, fileName, fileContent + '\n', onFileCreated);
function onFileCreated(err) {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Entering function."); }
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] start -> writeDataRange -> onFileCreated -> err = " + err.message);
callBack(err);
return;
}
if (LOG_FILE_CONTENT === true) {
logger.write(MODULE_NAME, "[INFO] start -> writeDataRange -> onFileCreated -> Content written = " + fileContent);
}
callBack(global.DEFAULT_OK_RESPONSE);
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> writeDataRange -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
}
}
function writeStatusReport(lastFileDate, callBack) {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> Entering function."); }
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> lastFileDate = " + lastFileDate); }
try {
let reportKey = bot.devTeam + "-" + bot.codeName + "-" + "Multi-Period-Daily" + "-" + "dataSet.V1";
let thisReport = statusDependencies.statusReports.get(reportKey);
thisReport.file.lastExecution = bot.currentDaytime;
thisReport.file.lastFile = lastFileDate;
thisReport.file.interExecutionMemoryArray = interExecutionMemoryArray;
thisReport.save(callBack);
bot.hasTheBotJustStarted = false;
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
};
+343
View File
@@ -0,0 +1,343 @@
exports.newMultiPeriodMarket = function newMultiPeriodMarket(bot, logger, COMMONS, UTILITIES, BLOB_STORAGE, USER_BOT_MODULE, COMMONS_MODULE) {
const FULL_LOG = true;
const LOG_FILE_CONTENT = false;
const MODULE_NAME = "Multi Period Market";
const EXCHANGE_NAME = "Poloniex";
const commons = COMMONS.newCommons(bot, logger, UTILITIES);
thisObject = {
initialize: initialize,
start: start
};
let utilities = UTILITIES.newCloudUtilities(bot, logger);
let statusDependencies;
let dataDependencies;
let storages = [];
let dataFiles = [];
let usertBot;
let processConfig;
return thisObject;
function initialize(pProcessConfig, pStatusDependencies, pDataDependencies, callBackFunction) {
try {
logger.fileName = MODULE_NAME;
logger.initialize();
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); }
statusDependencies = pStatusDependencies;
dataDependencies = pDataDependencies;
processConfig = pProcessConfig;
for (let i = 0; i < dataDependencies.config.length; i++) {
let key;
let storage;
let dependency = dataDependencies.config[i];
key = dependency.devTeam + "-" +
dependency.bot + "-" +
dependency.product + "-" +
dependency.dataSet + "-" +
dependency.dataSetVersion
storage = dataDependencies.dataSets.get(key);
storages.push(storage);
}
usertBot = USER_BOT_MODULE.newUserBot(bot, logger, COMMONS_MODULE, UTILITIES, BLOB_STORAGE);
usertBot.initialize(dataDependencies, callBackFunction);
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] initialize -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function start(callBackFunction) {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); }
let market = global.MARKET;
/* Context Variables */
let contextVariables = {
dateBeginOfMarket: undefined, // Datetime of the first trade file in the whole market history.
dateEndOfMarket: undefined // Datetime of the last file available to be used as an input of this process.
};
if (processConfig.framework.startDate.fixedDate !== undefined) {
/* The starting date is fixed, we will start from there. */
contextVariables.dateBeginOfMarket = new Date(processConfig.framework.startDate.fixedDate);
}
if (processConfig.framework.endDate.fixedDate !== undefined) {
/* The ending date is fixed, we will end there. */
contextVariables.dateEndOfMarket = new Date(processConfig.framework.endDate.fixedDate);
}
processTimePeriods();
function processTimePeriods() {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> Entering function."); }
try {
let n;
periodsLoop();
function periodsLoop() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoop -> Entering function."); }
/*
We will iterate through all posible periods.
*/
n = 0 // loop Variable representing each possible period as defined at the periods array.
periodsLoopBody();
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoop -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function periodsLoopBody() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> Entering function."); }
const timePeriod = global.marketFilesPeriods[n][0];
const outputPeriodLabel = global.marketFilesPeriods[n][1];
let dependencyIndex = 0;
dataFiles = [];
dependencyLoopBody();
function dependencyLoopBody() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> Entering function."); }
let dependency = dataDependencies.config[dependencyIndex];
let storage = storages[dependencyIndex];
getFile();
function getFile() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> Entering function."); }
let fileName = market.assetA + '_' + market.assetB + ".json";
let filePath = dependency.product + "/" + "Multi-Period-Market" + "/" + outputPeriodLabel;
storage.getTextFile(filePath, fileName, onFileReceived, true);
function onFileReceived(err, text) {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> Entering function."); }
if (LOG_FILE_CONTENT === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> text = " + text); }
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> err = " + err.message);
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> filePath = " + filePath);
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> fileName = " + fileName);
callBackFunction(err);
return;
}
let dataFile = JSON.parse(text);
dataFiles.push(dataFile);
dependencyControlLoop();
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> onFileReceived -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> dependencyLoopBody -> getFile -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoop -> dependencyLoopBody -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function dependencyControlLoop() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> dependencyControlLoop -> Entering function."); }
dependencyIndex++;
if (dependencyIndex < dataDependencies.config.length) {
dependencyLoopBody();
} else {
callTheBot();
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> dependencyControlLoop -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function callTheBot() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> Entering function."); }
const timePeriod = global.marketFilesPeriods[n][0];
const outputPeriodLabel = global.marketFilesPeriods[n][1];
usertBot.start(
dataFiles,
timePeriod,
outputPeriodLabel,
contextVariables.dateBeginOfMarket,
contextVariables.dateEndOfMarket,
onBotFinished);
function onBotFinished(err) {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> onBotFinished -> Entering function."); }
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
callBackFunction(err);
return;
}
periodsControlLoop();
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> onBotFinished -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
catch(err){
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> callTheBot -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsLoopBody -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function periodsControlLoop() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> processTimePeriods -> periodsControlLoop -> Entering function."); }
n++;
if (n < global.marketFilesPeriods.length) {
periodsLoopBody();
} else {
writeStatusReport(callBackFunction);
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> periodsControlLoop -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> processTimePeriods -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
function writeStatusReport(callBack) {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> writeStatusReport -> Entering function."); }
try {
let reportKey = bot.devTeam + "-" + bot.codeName + "-" + "Multi-Period-Market" + "-" + "dataSet.V1";
let thisReport = statusDependencies.statusReports.get(reportKey);
thisReport.file.lastExecution = bot.processDatetime;
thisReport.save(callBack);
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> writeStatusReport -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
}
catch (err) {
logger.write(MODULE_NAME, "[ERROR] start -> err = " + err.message);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
};
+19 -1
View File
@@ -33,6 +33,18 @@
<Compile Include="CloudRequire.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="MultiPeriodDaily.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="MultiPeriodMarket.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="utils\auth.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="utils\logger.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="DataDependencies.js">
<SubType>Code</SubType>
</Compile>
@@ -45,6 +57,9 @@
<Compile Include="exchange\wrappers\binanceClient.js" />
<Compile Include="exchange\wrappers\poloniex.js" />
<Compile Include="exchange\wrappers\poloniexClient.js" />
<Compile Include="Integrations\OperationsModuleIntegration.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="Root.js">
<SubType>Code</SubType>
</Compile>
@@ -68,6 +83,7 @@
<Compile Include="StatusReport.js">
<SubType>Code</SubType>
</Compile>
<Compile Include="StorageAccessManager.js" />
<Compile Include="TradingBotProcessMainLoop.js">
<SubType>Code</SubType>
</Compile>
@@ -81,7 +97,9 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Exchange\" />
<Folder Include="Exchange\Wrappers\" />
<Folder Include="Exchange\wrappers\" />
<Folder Include="Integrations\" />
<Folder Include="utils\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.Common.targets" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<!--Do not delete the following Import Project. While this appears to do nothing it is a marker for setting TypeScript properties before our import that depends on them.-->
+6 -4
View File
@@ -1,10 +1,12 @@
# AACloud
# Clone Executor
This repository holds the code of the bits of the AA Platform that run in the cloud.
Whithin the Superalgos project, we have the concept of Financial Beings, which are autonomous agents that have a financial life. These FBs entities have a master (imagine a class in programming) and clones (imagine an instance of a class running). The master is the one who aquires reputation after competitions. Every time we need to do a backtest, live trading or participating in a competition, a clone is extracted from the master and is put to run, either in backtest mode, live trading mode or competition mode. The clone lifespan is contrained by the purpose it was created. For instance, a clone created for a competition will live only during the period of such competition.
## About the AA Project
The software needed to execute these clones is the Clone Executor.
The AA Platform is built and maintained by Advanced Algos, the start up behind the AA Project.
## About the Superalgos Project
Superalgos is built and maintained by the Superalgos Foundation and its Community.
Our mission is to enable the fast-paced evolution of crypto trading bots within the context of trading bots competitions.
+540 -611
View File
File diff suppressed because it is too large. Load diff
+181 -97
View File
@@ -1,10 +1,10 @@
global.CURRENT_ENVIRONMENT = "Develop";
global.CURRENT_EXECUTION_AT = "Browser";
require('dotenv').config()
global.CURRENT_ENVIRONMENT = "Develop";
global.CURRENT_EXECUTION_AT = "Node";
global.SHALL_BOT_STOP = false;
global.USER_LOGGED_IN = "Ciencias";
global.DEV_TEAM = "AAMasters";
global.AT_BREAKPOINT = false; // This is used only when running at the browser.
global.AT_BREAKPOINT = false; // This is used only when running at the browser.
global.RUN_AS_TEAM = false;
/* Default parameters can be changed by the execution configuration */
global.EXCHANGE_NAME = "Poloniex";
@@ -15,13 +15,14 @@ global.MARKET = {
process.on('uncaughtException', function (err) {
console.log('[INFO] Run -> uncaughtException -> err.message = ' + err.message);
return;
console.log('[INFO] Run -> uncaughtException -> err.stack = ', err.stack);
throw new Error()
});
process.on('unhandledRejection', (reason, p) => {
console.log('[INFO] Run -> unhandledRejection -> reason = ' + reason);
console.log('[INFO] Run -> unhandledRejection -> p = ' + JSON.stringify(p));
return;
throw new Error()
});
process.on('exit', function (code) {
@@ -36,110 +37,193 @@ process.on('exit', function (code) {
}
});
global.USER_PROFILE = {};
global.EMAIL_CONFIG = {};
readExecutionConfiguration();
readStoragePermissions();
function readExecutionConfiguration() {
try {
console.log("[INFO] Run -> readExecutionConfiguration -> Entering function. ");
let startMode
// Environment Configuration
global.CURRENT_ENVIRONMENT = process.env.PLATFORM_ENVIRONMENT
global.GATEWAY_ENDPOINT = process.env.GATEWAY_ENDPOINT
// General Financial Being Configuration
global.DEV_TEAM = process.env.DEV_TEAM
global.CURRENT_BOT_REPO = process.env.BOT + "-" + process.env.TYPE + "-Bot"
global.RUN_AS_TEAM = (process.env.RUN_AS_TEAM === "true")
global.USER_LOGGED_IN = process.env.USER_LOGGED_IN
if (process.env.TYPE === 'Trading') {
let live = {
run: "false",
resumeExecution: process.env.RESUME_EXECUTION
}
let backtest = {
run: "false",
resumeExecution: process.env.RESUME_EXECUTION,
beginDatetime: process.env.BEGIN_DATE_TIME,
endDatetime: process.env.END_DATE_TIME,
waitTime: process.env.WAIT_TIME
}
let competition = {
run: "false",
resumeExecution: process.env.RESUME_EXECUTION,
beginDatetime: process.env.BEGIN_DATE_TIME,
endDatetime: process.env.END_DATE_TIME
}
startMode = {
live: live,
backtest: backtest,
competition: competition
}
} else if (process.env.TYPE === 'Indicator' || process.env.TYPE === 'Extraction') {
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: process.env.RESUME_EXECUTION
}
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"
let cloneToExecute = {
enabled: "true",
devTeam: process.env.DEV_TEAM,
bot: process.env.BOT,
process: process.env.PROCESS,
repo: global.CURRENT_BOT_REPO
}
global.EXECUTION_CONFIG = {
cloneToExecute: cloneToExecute,
startMode: startMode,
timePeriod: getTimePeriod(process.env.TIME_PERIOD),
timePeriodFileStorage: process.env.TIME_PERIOD,
dataSet: process.env.DATA_SET
};
readStoragePermissions();
}
catch (err) {
console.log("[ERROR] readExecutionConfiguration -> err = " + err.message);
console.log("[ERROR] readExecutionConfiguration -> Please verify that the Start Mode for the type of Bot configured applies to that type.");
console.log("[ERROR] readExecutionConfiguration -> err = " + err.stack);
}
}
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 readStoragePermissions() {
let filePath;
try {
console.log( "[INFO] Run -> readStoragePermissions -> Entering function. ");
let fs = require('fs');
filePath = '../' + 'User-Profile' + '/' + 'User.Profile.json';
global.USER_PROFILE = JSON.parse(fs.readFileSync(filePath, 'utf8'));
/* Dinamically generating the azure storage permissions for the bot to run */
global.STORAGE_BASE_URL = process.env.STORAGE_BASE_URL
global.USER_PROFILE = {}
const MAX_STORAGE_PERMISSION_DAYS = 10;
const STORAGE_ACCESS_MANAGER = require('./StorageAccessManager');
storageAccessManager = STORAGE_ACCESS_MANAGER.newStorageAccessManager();
storageAccessManager.initialize(process.env.STORAGE_CONNECTION_STRING, onInitialized);
/* Here we will rearrange the storage permissions array into a map, so that it can be easily consumed when needed. */
function onInitialized() {
let permissionsMap = new Map;
/* Here we will rearrange the storage permissions array into a map, so that it can be easily consumed when needed. */
for (i = 0; i < global.USER_PROFILE.storagePermissions.length; i++) {
let permissionsMap = new Map;
let permission = global.USER_PROFILE.storagePermissions[i];
let containers = ["AAPlatform", "AAMasters", "AAVikings", global.DEV_TEAM]
let container;
let key;
let value;
permissionsMap.set(permission[0], permission[1]);
for (let i = 0; i < containers.length; i++) {
container = containers[i];
let readPermission = storageAccessManager.getPermission(container.toLowerCase(), "READ", MAX_STORAGE_PERMISSION_DAYS);
key = container + ".READ";
value = readPermission;
permissionsMap.set(key, value);
}
let writePermission = storageAccessManager.getPermission(container.toLowerCase(), "WRITE", MAX_STORAGE_PERMISSION_DAYS);
key = container + ".WRITE";
value = writePermission;
permissionsMap.set(key, value);
global.USER_PROFILE.storagePermissions = permissionsMap;
global.USER_PROFILE.connectionString = "";
process.env.STORAGE_CONNECTION_STRING = "";
startRoot();
}
global.USER_PROFILE.storagePermissions = permissionsMap;
readEmailConfiguration();
}
catch (err) {
} catch (err) {
console.log("[ERROR] Run -> readStoragePermissions -> err = " + err.message);
console.log("[HINT] Run -> readStoragePermissions -> You need to have a file at this path -> " + filePath);
}
}
function readEmailConfiguration() {
let filePath;
try {
console.log( "Run : [INFO] readEmailConfiguration -> Entering function. ");
let fs = require('fs');
filePath = '../' + 'Email-Config' + '/' + 'Email.Config.json';
global.EMAIL_CONFIG = JSON.parse(fs.readFileSync(filePath, 'utf8'));
readExecutionConfiguration();
}
catch (err) {
console.log("[ERROR] Run -> readEmailConfiguration -> err = " + err.message);
console.log("[HINT] Run -> You need to have a file at this path -> " + filePath);
}
}
function readExecutionConfiguration() {
let filePath;
try {
let fs = require('fs');
filePath = '../Execution-Config/Execution.Config.json';
let executionProperties = JSON.parse(fs.readFileSync(filePath, 'utf8'));
global.DEV_TEAM = executionProperties.devTeam;
global.EXCHANGE_NAME = executionProperties.exchangeName;
global.MARKET = executionProperties.market;
global.EXECUTION_CONFIG = {
executionList: executionProperties.executionList,
startMode: executionProperties.startMode
};
readExchangeAPIKey();
}
catch (err) {
console.log("[ERROR] readExecutionConfiguration -> err = " + err.message);
console.log("[HINT] You need to have a file at this path -> " + filePath);
}
}
//TODO Move this method inside ExchangeAPI
function readExchangeAPIKey() {
try {
console.log( "[INFO] Run -> readExchangeAPIKey -> Entering function. ");
let fs = require('fs');
let filePath = '../' + 'Exchange-Keys' + '/' + 'Secret.Keys' + '.json';
global.EXCHANGE_KEYS = JSON.parse(fs.readFileSync(filePath, 'utf8'));
startRoot();
}
catch (err) {
console.log("[ERROR] Run -> readExchangeAPIKey -> err = " + err.message);
console.log("[HINT] Run -> You need to have a file at this path -> " + filePath);
global.EXCHANGE_KEYS = {
Poloniex: [{
Key: "",
Secret: ""
}]
}
startRoot();
}
}
+3
View File
@@ -6,6 +6,7 @@
const MODULE_NAME = "Status Dependencies";
let thisObject = {
config: undefined,
statusReports: new Map(),
initialize: initialize,
keys: []
@@ -22,6 +23,8 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); }
thisObject.config = pStatusDependenciesConfig;
/*
For each dependency declared at the bot config, we will initialize the status report, and load it as part of this initialization process.
+62
View File
@@ -0,0 +1,62 @@
exports.newStorageAccessManager = function newStorageAccessManager() {
let thisObject = {
getPermission: getPermission,
initialize: initialize
}
let connectionString;
return thisObject;
function initialize(pConnectionString, callBackFunction) {
connectionString = pConnectionString;
callBackFunction();
}
function getPermission(pContainer, pType, pDays) {
let azure = require('azure-storage');
let blobService = azure.createBlobService(connectionString);
let startDate = new Date();
startDate.setDate(startDate.getDate() - 1);
let expiryDate = new Date(startDate);
expiryDate.setDate(startDate.getDate() + pDays);
let azurePermissions;
switch (pType) {
case "READ": {
azurePermissions = azure.BlobUtilities.SharedAccessPermissions.READ;
break;
}
case "WRITE": {
azurePermissions = azure.BlobUtilities.SharedAccessPermissions.WRITE;
break;
}
case "DELETE": {
azurePermissions = azure.BlobUtilities.SharedAccessPermissions.DELETE;
break;
}
}
let blobName = undefined;
let sharedAccessPolicy = {
AccessPolicy: {
Permissions: azurePermissions,
Start: startDate,
Expiry: expiryDate
}
};
let sasToken = blobService.generateSharedAccessSignature(pContainer, blobName, sharedAccessPolicy);
return "BlobEndpoint=" + global.STORAGE_BASE_URL + ";SharedAccessSignature=" + sasToken + "";
}
}
+73 -76
View File
@@ -8,12 +8,13 @@
let USER_BOT_MODULE;
let COMMONS_MODULE;
const BLOB_STORAGE = require(ROOT_DIR + 'BlobStorage');
const operationsIntegration = require('./Integrations/OperationsModuleIntegration')
const BLOB_STORAGE = require(ROOT_DIR + 'BlobStorage');
const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog');
let logger; // We need this here in order for the loopHealth function to work and be able to rescue the loop when it gets in trouble.
let nextLoopTimeoutHandle;
let nextLoopTimeoutHandle;
let checkLoopHealthHandle;
let thisObject = {
@@ -24,7 +25,7 @@
bot["botCache"] = new Map();
let processConfig;
let cloudStorage;
let UI_COMMANDS;
let UI_COMMANDS;
return thisObject;
@@ -51,12 +52,13 @@
let filePath;
switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy.
case "Cloud": {
filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud.
break;
}
case "Browser": {
filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser.
case "Node": {
if (global.RUN_AS_TEAM) {
filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud.
} else {
filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO + "/" + pProcessConfig.name; // DevTeam Members bots only are run at the browser.
}
break;
}
case "IDE": {
@@ -64,7 +66,7 @@
break;
}
default: {
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'.");
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Node' or 'IDE'.");
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return;
@@ -87,23 +89,8 @@
USER_BOT_MODULE = pMODULE;
switch (global.CURRENT_EXECUTION_AT) {
case "Cloud": {
filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo;
break;
}
case "Browser": {
filePath = global.DEV_TEAM + "/" + "members" + "/" + global.USER_LOGGED_IN + "/" + global.CURRENT_BOT_REPO;
break;
}
default: {
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'.");
parentLogger.write(MODULE_NAME, "[ERROR] initialize -> onInizialized -> onBotDownloaded -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return;
}
}
filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo;
cloudRequire.downloadCommons(cloudStorage, filePath, onCommonsDownloaded);
function onCommonsDownloaded(err, pMODULE) {
@@ -134,10 +121,12 @@
function run(pGenes, pTotalAlgobots, callBackFunction) {
let context;
try {
if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, "[INFO] run -> Entering function."); }
bot.enableCheckLoopHealth = true;
bot.enableCheckLoopHealth = true;
let fixedTimeLoopIntervalHandle;
@@ -160,8 +149,6 @@
return str.length < max ? pad(" " + str, max) : str;
}
console.log(new Date().toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.instance, 20) + " " + pad(bot.process, 30) + " Entered into Main Loop # " + pad(Number(bot.loopCounter) + 1, 8));
/* For each loop we want to create a new log file. */
logger = DEBUG_MODULE.newDebugLog();
@@ -242,7 +229,7 @@
} else {
bot.processDatetime = new Date(bot.backtest.beginDatetime); // Set the starting time as the configured beginDatetime.
bot.processDatetime = new Date(bot.backtest.beginDatetime); // Set the starting time as the configured beginDatetime.
}
@@ -257,7 +244,7 @@
} else {
bot.processDatetime = new Date(bot.processDatetime.valueOf() + timePeriod); // We advance time here.
bot.processDatetime = new Date(bot.processDatetime.valueOf() + timePeriod); // We advance time here.
if (UI_COMMANDS.eventHandler !== undefined) {
@@ -270,15 +257,15 @@
if (UI_COMMANDS.endDatetime !== undefined) {
endDatetime = new Date(UI_COMMANDS.endDatetime.valueOf());
endDatetime = new Date(UI_COMMANDS.endDatetime.valueOf());
} else {
endDatetime = new Date(bot.backtest.endDatetime);
endDatetime = new Date(bot.backtest.endDatetime);
}
if (global.CURRENT_EXECUTION_AT === "Cloud") {
if (global.CURRENT_EXECUTION_AT === "Node") {
if (bot.processDatetime.valueOf() > endDatetime.valueOf()) {
@@ -317,7 +304,7 @@
}
if (global.CURRENT_EXECUTION_AT === "Cloud") {
if (global.CURRENT_EXECUTION_AT === "Node") {
let beginDatetime = new Date(bot.competition.beginDatetime);
@@ -361,7 +348,7 @@
}
}
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> bot.processDatetime = " + bot.processDatetime); }
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> bot.processDatetime = " + bot.processDatetime.toISOString()); }
if (global.AT_BREAKPOINT === true) {
@@ -369,9 +356,13 @@
}
/* High level log entry */
console.log(new Date().toISOString() + " " + pad(bot.codeName, 20) + " " + pad(bot.devTeam, 20) + " " + pad(bot.process, 30)
+ " " + bot.startMode + " Entered into Main Loop # " + pad(Number(bot.loopCounter), 8) + " bot.processDatetime = " + bot.processDatetime.toISOString());
/* We will prepare first the infraestructure needed for the bot to run. There are 3 modules we need to sucessfullly initialize first. */
let context;
let exchangeAPI;
let assistant;
let userBot;
@@ -527,7 +518,7 @@
callBackFunction(err);
}
}
function initializeContext() {
try {
@@ -607,7 +598,7 @@
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeExchangeAPI -> Entering function."); }
exchangeAPI = EXCHANGE_API.newExchangeAPI(bot, logger);
exchangeAPI = EXCHANGE_API.newExchangeAPI(logger);
exchangeAPI.initialize(onInizialized);
@@ -855,7 +846,6 @@
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
assistant.sendEmail("FAIL", "Operation Failed. Aborting the process. err = " + err.message, emailList = global.EMAIL_CONFIG.adminList);
callBackFunction(err);
return;
}
@@ -868,7 +858,6 @@
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
assistant.sendEmail("FAIL", "Operation Failed. Aborting the process. err = " + err.message, emailList = global.EMAIL_CONFIG.adminList);
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return;
}
@@ -881,7 +870,6 @@
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
assistant.sendEmail("FAIL", "Operation Failed. Aborting the process. err = " + err.message, emailList = global.EMAIL_CONFIG.adminList);
callBackFunction(err);
}
}
@@ -893,7 +881,6 @@
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
assistant.sendEmail("FAIL", "Operation Failed. Aborting the process. err = " + err.message, emailList = global.EMAIL_CONFIG.adminList);
callBackFunction(err);
}
}
@@ -916,7 +903,7 @@
case global.DEFAULT_OK_RESPONSE.result: {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> saveContext -> onFinished -> Execution finished well."); }
nextWaitTime = 'Normal';
loopControl(nextWaitTime);
updateClonesModule();
return;
}
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
@@ -975,6 +962,41 @@
}
}
async function updateClonesModule() {
try {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> updateClonesModule -> Entering function."); }
if (global.CURRENT_EXECUTION_AT === "Node") {
// Update clones module with latest context informations
let lastExecution = context.newHistoryRecord
let date = lastExecution.date / 1000 | 0
let buyAvgRate = lastExecution.buyAvgRate
let sellAvgRate = lastExecution.sellAvgRate
let marketRate = lastExecution.marketRate
let combinedProfitsA = lastExecution.combinedProfitsA
let combinedProfitsB = lastExecution.combinedProfitsB
await operationsIntegration.updateExecutionResults(date, buyAvgRate, sellAvgRate,
marketRate, combinedProfitsA, combinedProfitsB)
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> updateClonesModule -> Clones Module Updated."); }
}
nextWaitTime = 'Normal';
loopControl(nextWaitTime);
} catch (err) {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> updateClonesModule -> err = " + err.message);
logger.write(MODULE_NAME, "[ERROR] run -> loop -> updateClonesModule -> Execution will continue anyways. ");
nextWaitTime = 'Normal';
loopControl(nextWaitTime);
}
}
function loopControl(nextWaitTime) {
if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Entering function."); }
@@ -1038,7 +1060,7 @@
function checkLoopHealth(pLastLoop) {
if (global.CURRENT_EXECUTION_AT !== "Cloud") {
if (global.CURRENT_EXECUTION_AT !== "Node") {
return;
}
@@ -1090,34 +1112,8 @@
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
let filePath;
switch (global.CURRENT_EXECUTION_AT) { // This is what determines if the bot is loaded from the devTeam or an endUser copy.
case "Cloud": {
filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud.
break;
}
case "Browser": {
if (global.SHALL_BOT_STOP === false) {
continueCallBack();
} else {
stopCallBack();
}
return;
}
default: {
logger.write(MODULE_NAME, "[ERROR] run -> loop -> shallWeStop -> onInizialized -> CURRENT_EXECUTION_AT must be either 'Cloud' or 'Browser'.");
logger.write(MODULE_NAME, "[ERROR] run -> loop -> shallWeStop -> onInizialized -> global.CURRENT_EXECUTION_AT = " + global.CURRENT_EXECUTION_AT);
logger.persist();
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
bot.enableCheckLoopHealth = false;
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return;
}
}
let filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud.
let fileName = "this.config.json";
cloudStorage.getTextFile(filePath, fileName, onFileReceived);
@@ -1126,7 +1122,7 @@
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
/*
/*
If for any reason this config file cannot be read, we are not going to abort the loop for that. Instead we are going to assume
that there are no instructions to stop and we will keep the show running.
*/
@@ -1176,7 +1172,7 @@
}
} catch (err) {
parentLogger.write(MODULE_NAME, "[ERROR] run -> loop -> err = " + err.message);
parentLogger.write(MODULE_NAME, "[ERROR] run -> loop -> err = " + err.stack);
clearInterval(fixedTimeLoopIntervalHandle);
clearTimeout(nextLoopTimeoutHandle);
clearTimeout(checkLoopHealthHandle);
@@ -1184,6 +1180,7 @@
callBackFunction(err);
}
}
}
catch (err) {
+570 -126
View File
File diff suppressed because it is too large. Load diff
+6 -3
View File
@@ -11,14 +11,17 @@
"dependencies": {
"apollo-boost": "^0.1.16",
"assert": "^1.4.1",
"axios": "^0.18.0",
"azure-storage": "^2.8.2",
"dotenv": "^6.0.0",
"graphql": "^14.0.2",
"graphql-client": "^2.0.1",
"jsonwebtoken": "^8.4.0",
"lodash": "^4.17.11",
"nodemailer": "^4.6.8",
"nonce": "^1.0.4",
"querystring": "^0.2.0",
"request": "^2.88.0",
"retry": "^0.12.0",
"underscore": "^1.9.1"
"underscore": "^1.9.1",
"winston": "^3.1.0"
}
}
-44
View File
@@ -5,50 +5,6 @@
"minor": 1,
"patch": 0
},
"executionList": [
{
"enabled": "false",
"devTeam": "AAMasters",
"bot": "AAMariam",
"process": "Trading-Process",
"repo": "AAMariam-Trading-Bot"
},
{
"enabled": "true",
"devTeam": "AAMasters",
"bot": "AACharly",
"process": "Poloniex-Live-Trades",
"repo": "AACharly-Extraction-Bot"
},
{
"enabled": "true",
"devTeam": "AAMasters",
"bot": "AACharly",
"process": "Poloniex-Hole-Fixing",
"repo": "AACharly-Extraction-Bot"
},
{
"enabled": "true",
"devTeam": "AAMasters",
"bot": "AABruce",
"process": "One-Min-Daily-Candles-Volumes",
"repo": "AABruce-Indicator-Bot"
},
{
"enabled": "true",
"devTeam": "AAMasters",
"bot": "AAOlivia",
"process": "Multi-Period-Daily",
"repo": "AAOlivia-Indicator-Bot"
},
{
"enabled": "true",
"devTeam": "AAMasters",
"bot": "AAOlivia",
"process": "Multi-Period-Market",
"repo": "AAOlivia-Indicator-Bot"
}
],
"stopGracefully": false,
"marketRateProvider": {
"devTeam": "AAMasters",
+35
View File
@@ -0,0 +1,35 @@
const axios = require('axios')
exports.authenticate = async function () {
try {
if (!global.ACCESS_TOKEN) {
const authBody = '{"client_id":"' + process.env.AUTH_CLIENT_ID
+ '","client_secret": "' + process.env.AUTH_CLIENT_SECRET
+ '","audience":"' + process.env.AUTH_AUDIENCE
+ '","grant_type":"client_credentials"}'
let authResponse = await axios({
url: process.env.AUTH_URL,
method: 'post',
data: authBody,
headers: { 'content-type': 'application/json' }
})
if (!authResponse.data.errors)
global.ACCESS_TOKEN = authResponse.data.access_token
else throw new Error(operationsResponse.data.errors[0].message)
process.env.AUTH_CLIENT_ID = ""
process.env.AUTH_CLIENT_SECRET = ""
process.env.AUTH_AUDIENCE = ""
process.env.AUTH_URL = ""
}
return global.ACCESS_TOKEN
} catch (error) {
throw new Error('There has been an error on the authentication: ' + error)
}
}
+39
View File
@@ -0,0 +1,39 @@
const winston = require('winston')
const util = require('util')
const options = {
file: {
level: 'info',
filename: '../logs/app.log',
handleExceptions: true,
json: true,
maxsize: 5242880, // 5MB
maxFiles: 5,
colorize: false,
timestamp: true
},
console: {
level: 'debug',
handleExceptions: true,
json: false,
colorize: true,
timestamp: true
}
}
exports.logger = winston.createLogger({
level: 'info',
format: winston.format.combine(
winston.format.colorize(),
winston.format.splat(),
winston.format.timestamp({ format: 'YY/MM/DD HH:mm' }),
winston.format.printf(
info => `${info.timestamp} - ${info.level}: ${JSON.parse(JSON.stringify(util.inspect(info.message)))}`
)
),
transports: [
new winston.transports.File(options.file),
new winston.transports.Console(options.console)
],
exitOnError: false // do not exit on handled exceptions
})