Allows Paralell Run on Live and Backtest from different IDEs
This commit is contained in:
1 parent
6cc0e83d65
commit
afb781e442
7 files changed
+466
-730
No files matched your search
Binary file not shown.
+234
-111
@@ -91,78 +91,128 @@
|
||||
try {
|
||||
candleArray = JSON.parse(text);
|
||||
|
||||
if (bot.backTestingMode === true) {
|
||||
switch (bot.runMode) {
|
||||
|
||||
logger.write("[INFO] initialize -> getMarketRate -> onFileReceived -> Backtest Mode detected.");
|
||||
case "Live": {
|
||||
|
||||
/* We need to find the candle at which the process is currently running. */
|
||||
logger.write("[INFO] initialize -> getMarketRate -> onFileReceived -> Live Mode detected.");
|
||||
|
||||
for (let i = 0; i < candleArray.length; i++) {
|
||||
let lastCandleRecord = candleArray[candleArray.length - 1]; // The last candle contains at its close value the market rate.
|
||||
|
||||
let candle = {
|
||||
open: candleArray[i][2],
|
||||
close: candleArray[i][3],
|
||||
min: candleArray[i][0],
|
||||
max: candleArray[i][1],
|
||||
begin: candleArray[i][4],
|
||||
end: candleArray[i][5]
|
||||
open: lastCandleRecord[2],
|
||||
close: lastCandleRecord[3],
|
||||
min: lastCandleRecord[0],
|
||||
max: lastCandleRecord[1],
|
||||
begin: lastCandleRecord[4],
|
||||
end: lastCandleRecord[5]
|
||||
};
|
||||
|
||||
if (bot.processDatetime.valueOf() >= candle.begin && bot.processDatetime.valueOf() < candle.end) {
|
||||
marketRate = candle.close;
|
||||
marketRate = Number(marketRate.toFixed(8));
|
||||
|
||||
marketRate = (candle.open + candle.close) / 2;
|
||||
marketRate = Number(marketRate.toFixed(8));
|
||||
/*
|
||||
Now we verify that this candle is not too old. Lets say no more than 10 minutes old. This could happen if the datasets for
|
||||
any reason stops being updated.
|
||||
*/
|
||||
|
||||
/* The Backtest Mode simulates that every trade posted is executed.
|
||||
In order to do this, we will take all open orders from the context and create a trades array similar to the one returned by the Exchange. */
|
||||
let delay = (bot.processDatetime.valueOf() - candle.begin) / 1000 / 60;
|
||||
|
||||
validateExchangeSyncronicity();
|
||||
logger.write("[INFO] initialize -> getMarketRate -> onFileReceived -> Market Rate " + delay + " minutes old.");
|
||||
|
||||
if (delay > 30) {
|
||||
|
||||
logger.write("[ERROR] initialize -> getMarketRate -> onFileReceived -> Market Rate more than 10 minutes old. Retrying later.");
|
||||
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
logger.write("[ERROR] initialize -> getMarketRate -> onFileReceived -> No candle found for the current Process Datetime.");
|
||||
logger.write("[ERROR] initialize -> getMarketRate -> onFileReceived -> bot.processDatetime = " + bot.processDatetime);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
|
||||
} else { // We are running LIVE Mode.
|
||||
|
||||
logger.write("[INFO] initialize -> getMarketRate -> onFileReceived -> Live Mode detected.");
|
||||
|
||||
let lastCandleRecord = candleArray[candleArray.length - 1]; // The last candle contains at its close value the market rate.
|
||||
|
||||
let candle = {
|
||||
open: lastCandleRecord[2],
|
||||
close: lastCandleRecord[3],
|
||||
min: lastCandleRecord[0],
|
||||
max: lastCandleRecord[1],
|
||||
begin: lastCandleRecord[4],
|
||||
end: lastCandleRecord[5]
|
||||
};
|
||||
|
||||
marketRate = candle.close;
|
||||
marketRate = Number(marketRate.toFixed(8));
|
||||
|
||||
/*
|
||||
Now we verify that this candle is not too old. Lets say no more than 2 minutes old. This could happen if the datasets for
|
||||
any reason stops being updated.
|
||||
*/
|
||||
|
||||
let delay = (bot.processDatetime.valueOf() - candle.begin) / 1000 / 60;
|
||||
|
||||
logger.write("[INFO] initialize -> getMarketRate -> onFileReceived -> Market Rate " + delay + " minutes old." );
|
||||
|
||||
if (delay > 30) {
|
||||
|
||||
logger.write("[ERROR] initialize -> getMarketRate -> onFileReceived -> Market Rate more than 10 minutes old. Retrying later.");
|
||||
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
validateExchangeSyncronicity();
|
||||
return;
|
||||
}
|
||||
|
||||
validateExchangeSyncronicity();
|
||||
return;
|
||||
case "Backtest": {
|
||||
|
||||
logger.write("[INFO] initialize -> getMarketRate -> onFileReceived -> Backtest Mode detected.");
|
||||
|
||||
/* We need to find the candle at which the process is currently running. */
|
||||
|
||||
for (let i = 0; i < candleArray.length; i++) {
|
||||
|
||||
let candle = {
|
||||
open: candleArray[i][2],
|
||||
close: candleArray[i][3],
|
||||
min: candleArray[i][0],
|
||||
max: candleArray[i][1],
|
||||
begin: candleArray[i][4],
|
||||
end: candleArray[i][5]
|
||||
};
|
||||
|
||||
if (bot.processDatetime.valueOf() >= candle.begin && bot.processDatetime.valueOf() < candle.end) {
|
||||
|
||||
marketRate = (candle.open + candle.close) / 2;
|
||||
marketRate = Number(marketRate.toFixed(8));
|
||||
|
||||
/* The Backtest Mode simulates that every trade posted is executed.
|
||||
In order to do this, we will take all open orders from the context and create a trades array similar to the one returned by the Exchange. */
|
||||
|
||||
validateExchangeSyncronicity();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
logger.write("[ERROR] initialize -> getMarketRate -> onFileReceived -> No candle found for the current Process Datetime.");
|
||||
logger.write("[ERROR] initialize -> getMarketRate -> onFileReceived -> bot.processDatetime = " + bot.processDatetime);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
case "Competition": {
|
||||
|
||||
logger.write("[INFO] initialize -> getMarketRate -> onFileReceived -> Competition Mode detected.");
|
||||
|
||||
let lastCandleRecord = candleArray[candleArray.length - 1]; // The last candle contains at its close value the market rate.
|
||||
|
||||
let candle = {
|
||||
open: lastCandleRecord[2],
|
||||
close: lastCandleRecord[3],
|
||||
min: lastCandleRecord[0],
|
||||
max: lastCandleRecord[1],
|
||||
begin: lastCandleRecord[4],
|
||||
end: lastCandleRecord[5]
|
||||
};
|
||||
|
||||
marketRate = candle.close;
|
||||
marketRate = Number(marketRate.toFixed(8));
|
||||
|
||||
/*
|
||||
Now we verify that this candle is not too old. Lets say no more than 10 minutes old. This could happen if the datasets for
|
||||
any reason stops being updated.
|
||||
*/
|
||||
|
||||
let delay = (bot.processDatetime.valueOf() - candle.begin) / 1000 / 60;
|
||||
|
||||
logger.write("[INFO] initialize -> getMarketRate -> onFileReceived -> Market Rate " + delay + " minutes old.");
|
||||
|
||||
if (delay > 30) {
|
||||
|
||||
logger.write("[ERROR] initialize -> getMarketRate -> onFileReceived -> Market Rate more than 10 minutes old. Retrying later.");
|
||||
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
validateExchangeSyncronicity();
|
||||
return;
|
||||
}
|
||||
|
||||
default: {
|
||||
logger.write("[ERROR] initialize -> getMarketRate -> onFileReceived -> Unexpected bot.runMode.");
|
||||
logger.write("[ERROR] initialize -> getMarketRate -> onFileReceived -> bot.runMode = " + bot.runMode);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
@@ -250,18 +300,36 @@
|
||||
|
||||
*/
|
||||
|
||||
if (bot.backTestingMode === true) {
|
||||
switch (bot.runMode) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] getPositionsAtExchange -> Backtest Mode Detected."); }
|
||||
case "Live": {
|
||||
|
||||
let exchangePositions = []; // We simulate all positions were executed.
|
||||
if (FULL_LOG === true) { logger.write("[INFO] getPositionsAtExchange -> Live Mode Detected."); }
|
||||
exchangeAPI.getOpenPositions(global.MARKET, onResponse);
|
||||
break;
|
||||
}
|
||||
|
||||
onResponse(global.DEFAULT_OK_RESPONSE, exchangePositions);
|
||||
} else {
|
||||
case "Backtest": {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] getPositionsAtExchange -> Live Mode Detected."); }
|
||||
exchangeAPI.getOpenPositions(global.MARKET, onResponse);
|
||||
if (FULL_LOG === true) { logger.write("[INFO] getPositionsAtExchange -> Backtest Mode Detected."); }
|
||||
let exchangePositions = []; // We simulate all positions were executed.
|
||||
onResponse(global.DEFAULT_OK_RESPONSE, exchangePositions);
|
||||
break;
|
||||
}
|
||||
|
||||
case "Competition": {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] getPositionsAtExchange -> Competition Mode Detected."); }
|
||||
exchangeAPI.getOpenPositions(global.MARKET, onResponse);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
logger.write("[ERROR] getPositionsAtExchange -> Unexpected bot.runMode.");
|
||||
logger.write("[ERROR] getPositionsAtExchange -> bot.runMode = " + bot.runMode);
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function onResponse(err, pExchangePositions) {
|
||||
@@ -481,47 +549,66 @@
|
||||
|
||||
*/
|
||||
|
||||
if (bot.backTestingMode === true) {
|
||||
switch (bot.runMode) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> Backtest Mode Detected."); }
|
||||
case "Live": {
|
||||
|
||||
let trades = [];
|
||||
if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> Live Mode Detected."); }
|
||||
exchangeAPI.getExecutedTrades(pPositionId, onResponse);
|
||||
return;
|
||||
|
||||
/* We look for the position at the executionContext */
|
||||
|
||||
for (let i = 0; i < context.executionContext.positions.length; i++) {
|
||||
|
||||
let thisPosition = context.executionContext.positions[i];
|
||||
|
||||
if (thisPosition.id === pPositionId) {
|
||||
|
||||
let trade = {
|
||||
id: Math.trunc(Math.random(1) * 1000000),
|
||||
type: thisPosition.type,
|
||||
rate: thisPosition.rate,
|
||||
amountA: thisPosition.amountA,
|
||||
amountB: thisPosition.amountB,
|
||||
fee: 0,
|
||||
date: (new Date()).valueOf()
|
||||
}
|
||||
|
||||
trades.push(trade);
|
||||
|
||||
onResponse(global.DEFAULT_OK_RESPONSE, trades);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
logger.write("[ERROR] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> Position not found at Executioin Context.");
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
case "Backtest": {
|
||||
|
||||
} else {
|
||||
if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> Backtest Mode Detected."); }
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> Live Mode Detected."); }
|
||||
exchangeAPI.getExecutedTrades(pPositionId, onResponse);
|
||||
let trades = [];
|
||||
|
||||
/* We look for the position at the executionContext */
|
||||
|
||||
for (let i = 0; i < context.executionContext.positions.length; i++) {
|
||||
|
||||
let thisPosition = context.executionContext.positions[i];
|
||||
|
||||
if (thisPosition.id === pPositionId) {
|
||||
|
||||
let trade = {
|
||||
id: Math.trunc(Math.random(1) * 1000000),
|
||||
type: thisPosition.type,
|
||||
rate: thisPosition.rate,
|
||||
amountA: thisPosition.amountA,
|
||||
amountB: thisPosition.amountB,
|
||||
fee: 0,
|
||||
date: (new Date()).valueOf()
|
||||
}
|
||||
|
||||
trades.push(trade);
|
||||
|
||||
onResponse(global.DEFAULT_OK_RESPONSE, trades);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
logger.write("[ERROR] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> Position not found at Executioin Context.");
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
|
||||
case "Competition": {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> Competition Mode Detected."); }
|
||||
exchangeAPI.getExecutedTrades(pPositionId, onResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
default: {
|
||||
logger.write("[ERROR] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> Unexpected bot.runMode.");
|
||||
logger.write("[ERROR] ordersExecutionCheck -> loopBody -> positionNotFound -> getPositionTradesAtExchange -> bot.runMode = " + bot.runMode);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function onResponse(err, pTrades) {
|
||||
@@ -839,22 +926,40 @@
|
||||
|
||||
/* All validations passed, we proceed. */
|
||||
|
||||
if (bot.backTestingMode === true) {
|
||||
switch (bot.runMode) {
|
||||
|
||||
if (pRate !== marketRate) {
|
||||
case "Live": {
|
||||
|
||||
logger.write("[ERROR] putPosition -> Input Validations -> putPosition Rate can not be different to marketRate while in Backtesting Mode. ");
|
||||
onResponse(global.DEFAULT_FAIL_RESPONSE, positionId);
|
||||
exchangeAPI.putPosition(global.MARKET, pType, pRate, pAmountA, pAmountB, onResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
let positionId = Math.trunc(Math.random(1) * 1000000);
|
||||
if (FULL_LOG === true) { logger.write("[INFO] putPosition -> Simulating Exchange Response -> orderId = " + positionId); }
|
||||
onResponse(global.DEFAULT_OK_RESPONSE, positionId);
|
||||
case "Backtest": {
|
||||
|
||||
} else {
|
||||
if (pRate !== marketRate) {
|
||||
|
||||
exchangeAPI.putPosition(global.MARKET, pType, pRate, pAmountA, pAmountB, onResponse);
|
||||
logger.write("[ERROR] putPosition -> Input Validations -> putPosition Rate can not be different to marketRate while in Backtesting Mode. ");
|
||||
onResponse(global.DEFAULT_FAIL_RESPONSE, positionId);
|
||||
}
|
||||
|
||||
let positionId = Math.trunc(Math.random(1) * 1000000);
|
||||
if (FULL_LOG === true) { logger.write("[INFO] putPosition -> Simulating Exchange Response -> orderId = " + positionId); }
|
||||
onResponse(global.DEFAULT_OK_RESPONSE, positionId);
|
||||
return;
|
||||
}
|
||||
|
||||
case "Competition": {
|
||||
|
||||
exchangeAPI.putPosition(global.MARKET, pType, pRate, pAmountA, pAmountB, onResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
default: {
|
||||
logger.write("[ERROR] putPosition -> Unexpected bot.runMode.");
|
||||
logger.write("[ERROR] putPosition -> bot.runMode = " + bot.runMode);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function onResponse(err, pPositionId) {
|
||||
@@ -938,16 +1043,34 @@
|
||||
if (FULL_LOG === true) { logger.write("[INFO] movePosition -> pPosition = " + JSON.stringify(pPosition)); }
|
||||
if (FULL_LOG === true) { logger.write("[INFO] movePosition -> pNewRate = " + pNewRate); }
|
||||
|
||||
if (bot.backTestingMode === true) {
|
||||
switch (bot.runMode) {
|
||||
|
||||
let positionId = Math.trunc(Math.random(1) * 1000000);
|
||||
if (FULL_LOG === true) { logger.write("[INFO] putPosition -> Simulating Exchange Response -> orderId = " + positionId); }
|
||||
onResponse(global.DEFAULT_OK_RESPONSE, positionId);
|
||||
case "Live": {
|
||||
|
||||
} else {
|
||||
exchangeAPI.movePosition(pPosition, pNewRate, onResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
exchangeAPI.movePosition(pPosition, pNewRate, onResponse);
|
||||
case "Backtest": {
|
||||
|
||||
let positionId = Math.trunc(Math.random(1) * 1000000);
|
||||
if (FULL_LOG === true) { logger.write("[INFO] putPosition -> Simulating Exchange Response -> orderId = " + positionId); }
|
||||
onResponse(global.DEFAULT_OK_RESPONSE, positionId);
|
||||
return;
|
||||
}
|
||||
|
||||
case "Competition": {
|
||||
|
||||
exchangeAPI.movePosition(pPosition, pNewRate, onResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
default: {
|
||||
logger.write("[ERROR] movePosition -> Unexpected bot.runMode.");
|
||||
logger.write("[ERROR] movePosition -> bot.runMode = " + bot.runMode);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function onResponse(err, pPositionId) {
|
||||
|
||||
+99
-46
@@ -78,6 +78,8 @@
|
||||
|
||||
let statusDependencies;
|
||||
|
||||
let runIndex; // This is the index for this run and depends on the runMode.
|
||||
|
||||
return thisObject;
|
||||
|
||||
function initialize(pStatusDependencies, callBackFunction) {
|
||||
@@ -166,6 +168,34 @@
|
||||
|
||||
} else {
|
||||
|
||||
switch (bot.runMode) {
|
||||
|
||||
case "Live": {
|
||||
|
||||
runIndex = thisObject.statusReport.liveRuns.length - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case "Backtest": {
|
||||
|
||||
runIndex = thisObject.statusReport.backtestRuns.length - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case "Competition": {
|
||||
|
||||
runIndex = thisObject.statusReport.competitionRuns.length - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
logger.write("[ERROR] initialize -> createConext -> Unexpected bot.runMode.");
|
||||
logger.write("[ERROR] initialize -> createConext -> bot.runMode = " + bot.runMode);
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
getExecutionHistory(callBack);
|
||||
|
||||
}
|
||||
@@ -182,7 +212,7 @@
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] initialize -> getExecutionHistory -> Entering function."); }
|
||||
|
||||
let fileName = "Execution.History." + thisObject.statusReport.runType + "." + thisObject.statusReport.runIndex + ".json";
|
||||
let fileName = "Execution.History." + bot.runMode + "." + runIndex + ".json";
|
||||
let filePath = bot.filePathRoot + "/Output/" + bot.process;
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] initialize -> getExecutionHistory -> fileName = " + fileName); }
|
||||
@@ -208,9 +238,12 @@
|
||||
|
||||
/* Move some values to the new record, in case there are no transactions that re-calculate them. */
|
||||
|
||||
thisObject.newHistoryRecord.buyAvgRate = thisObject.executionHistory[thisObject.executionHistory.length - 1][1];
|
||||
thisObject.newHistoryRecord.buyAvgRate = thisObject.executionHistory[thisObject.executionHistory.length-1][1];
|
||||
thisObject.newHistoryRecord.sellAvgRate = thisObject.executionHistory[thisObject.executionHistory.length - 1][2];
|
||||
|
||||
thisObject.newHistoryRecord.buyAvgRate = thisObject.executionHistory[1];
|
||||
thisObject.newHistoryRecord.sellAvgRate = thisObject.executionHistory[2];
|
||||
|
||||
getExecutionContext(callBack);
|
||||
|
||||
} catch (err) {
|
||||
@@ -241,25 +274,37 @@
|
||||
if (FULL_LOG === true) { logger.write("[INFO] initialize -> getExecutionContext -> Entering function."); }
|
||||
|
||||
let date;
|
||||
let runType = thisObject.statusReport.runType;
|
||||
|
||||
switch (runType) {
|
||||
switch (bot.runMode) {
|
||||
|
||||
case "Backtest": {
|
||||
date = new Date(thisObject.statusReport.backtestRuns[thisObject.statusReport.runIndex].lastExecution);
|
||||
thisObject.statusReport.backtestRuns[thisObject.statusReport.runIndex].lastExecution = bot.processDatetime;
|
||||
case "Live": {
|
||||
date = new Date(thisObject.statusReport.liveRuns[runIndex].lastExecution);
|
||||
thisObject.statusReport.liveRuns[runIndex].lastExecution = bot.processDatetime;
|
||||
thisObject.statusReport.liveRuns[runIndex].endDatetime = bot.processDatetime;
|
||||
break;
|
||||
}
|
||||
|
||||
case "Live": {
|
||||
date = new Date(thisObject.statusReport.liveRuns[thisObject.statusReport.runIndex].lastExecution);
|
||||
thisObject.statusReport.liveRuns[thisObject.statusReport.runIndex].lastExecution = bot.processDatetime;
|
||||
thisObject.statusReport.liveRuns[thisObject.statusReport.runIndex].endDatetime = bot.processDatetime;
|
||||
case "Backtest": {
|
||||
date = new Date(thisObject.statusReport.backtestRuns[runIndex].lastExecution);
|
||||
thisObject.statusReport.backtestRuns[runIndex].lastExecution = bot.processDatetime;
|
||||
break;
|
||||
}
|
||||
|
||||
case "Competition": {
|
||||
date = new Date(thisObject.statusReport.competitionRuns[runIndex].lastExecution);
|
||||
thisObject.statusReport.competitionRuns[runIndex].lastExecution = bot.processDatetime;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
logger.write("[ERROR] initialize -> getExecutionContext -> Unexpected bot.runMode.");
|
||||
logger.write("[ERROR] initialize -> getExecutionContext -> bot.runMode = " + bot.runMode);
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let fileName = "Execution.Context." + thisObject.statusReport.runType + "." + thisObject.statusReport.runIndex + ".json";
|
||||
let fileName = "Execution.Context." + bot.runMode + "." + runIndex + ".json";
|
||||
let dateForPath = date.getUTCFullYear() + '/' + utilities.pad(date.getUTCMonth() + 1, 2) + '/' + utilities.pad(date.getUTCDate(), 2) + '/' + utilities.pad(date.getUTCHours(), 2) + '/' + utilities.pad(date.getUTCMinutes(), 2);
|
||||
let filePath = bot.filePathRoot + "/Output/" + bot.process + '/' + dateForPath;
|
||||
|
||||
@@ -327,43 +372,18 @@
|
||||
|
||||
*/
|
||||
|
||||
let runType;
|
||||
|
||||
if (bot.backTestingMode === true) {
|
||||
runType = "Backtest";
|
||||
} else {
|
||||
runType = "Live";
|
||||
}
|
||||
|
||||
/* Here, we dont know if the Status Report was ever created or not. To test that we do this. */
|
||||
|
||||
if (thisObject.statusReport.runType === undefined) { // This means that the Status Report does not exist.
|
||||
if (thisObject.statusReport.liveRuns === undefined) { // This means that the Status Report does not exist.
|
||||
|
||||
thisObject.statusReport = {
|
||||
runType: runType,
|
||||
runIndex: 0,
|
||||
liveRuns: [],
|
||||
backtestRuns: []
|
||||
backtestRuns: [],
|
||||
competitionRuns: []
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
thisObject.statusReport.runType = runType;
|
||||
|
||||
switch (runType) {
|
||||
|
||||
case "Backtest": {
|
||||
|
||||
let runContent = {
|
||||
beginDatetime: (new Date(bot.timePeriod.beginDatetime)).valueOf(),
|
||||
endDatetime: (new Date(bot.timePeriod.endDatetime)).valueOf(),
|
||||
lastExecution: bot.processDatetime
|
||||
};
|
||||
|
||||
thisObject.statusReport.backtestRuns.push(runContent);
|
||||
thisObject.statusReport.runIndex = thisObject.statusReport.backtestRuns.length - 1;
|
||||
break;
|
||||
}
|
||||
switch (bot.runMode) {
|
||||
|
||||
case "Live": {
|
||||
|
||||
@@ -374,9 +394,42 @@
|
||||
};
|
||||
|
||||
thisObject.statusReport.liveRuns.push(runContent);
|
||||
thisObject.statusReport.runIndex = thisObject.statusReport.liveRuns.length - 1;
|
||||
runIndex = thisObject.statusReport.liveRuns.length - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case "Backtest": {
|
||||
|
||||
let runContent = {
|
||||
beginDatetime: (new Date(bot.backtest.beginDatetime)).valueOf(),
|
||||
endDatetime: (new Date(bot.backtest.endDatetime)).valueOf(),
|
||||
lastExecution: bot.processDatetime
|
||||
};
|
||||
|
||||
thisObject.statusReport.backtestRuns.push(runContent);
|
||||
runIndex = thisObject.statusReport.backtestRuns.length - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
case "Competition": {
|
||||
|
||||
let runContent = {
|
||||
beginDatetime: (new Date(bot.competition.beginDatetime)).valueOf(),
|
||||
endDatetime: (new Date(bot.competition.endDatetime)).valueOf(),
|
||||
lastExecution: bot.processDatetime
|
||||
};
|
||||
|
||||
thisObject.statusReport.competitionRuns.push(runContent);
|
||||
runIndex = thisObject.statusReport.competitionRuns.length - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
logger.write("[ERROR] initialize -> createConext -> Unexpected bot.runMode.");
|
||||
logger.write("[ERROR] initialize -> createConext -> bot.runMode = " + bot.runMode);
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
thisObject.executionHistory = [];
|
||||
@@ -469,7 +522,7 @@
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] saveThemAll -> writeExecutionContext -> Entering function."); }
|
||||
|
||||
let fileName = "Execution.Context." + thisObject.statusReport.runType + "." + thisObject.statusReport.runIndex +".json";
|
||||
let fileName = "Execution.Context." + bot.runMode + "." + runIndex +".json";
|
||||
let dateForPath = bot.processDatetime.getUTCFullYear() + '/' + utilities.pad(bot.processDatetime.getUTCMonth() + 1, 2) + '/' + utilities.pad(bot.processDatetime.getUTCDate(), 2) + '/' + utilities.pad(bot.processDatetime.getUTCHours(), 2) + '/' + utilities.pad(bot.processDatetime.getUTCMinutes(), 2);
|
||||
let filePath = bot.filePathRoot + "/Output/" + bot.process + '/' + dateForPath;
|
||||
|
||||
@@ -530,7 +583,7 @@
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] saveThemAll -> writeExucutionHistory -> Entering function."); }
|
||||
|
||||
let fileName = "Execution.History." + thisObject.statusReport.runType + "." + thisObject.statusReport.runIndex + ".json";
|
||||
let fileName = "Execution.History." + bot.runMode + "." + runIndex + ".json";
|
||||
let filePath = bot.filePathRoot + "/Output/" + bot.process;
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] saveThemAll -> writeExucutionHistory -> fileName = " + fileName); }
|
||||
@@ -586,8 +639,8 @@
|
||||
|
||||
/* Here we will write the file containing the max sequence number. */
|
||||
|
||||
fileContent = thisObject.statusReport.runIndex;
|
||||
fileName = "Execution.History." + thisObject.statusReport.runType + "." + "Sequence" + ".json";
|
||||
fileContent = runIndex;
|
||||
fileName = "Execution.History." + bot.runMode + "." + "Sequence" + ".json";
|
||||
filePath = bot.filePathRoot + "/Output/" + bot.process;
|
||||
|
||||
cloudStorage.createTextFile(filePath, fileName, fileContent + '\n', onSequenceFileCreated);
|
||||
|
||||
-526
@@ -1,526 +0,0 @@
|
||||
exports.newDatasource = function newDatasource(BOT, DEBUG_MODULE, BLOB_STORAGE, UTILITIES) {
|
||||
|
||||
const FULL_LOG = true;
|
||||
|
||||
/*
|
||||
|
||||
This module allows trading bots to access information stored at the cloud storage.
|
||||
|
||||
*/
|
||||
|
||||
const MODULE_NAME = "Datasource";
|
||||
|
||||
let thisObject = {
|
||||
initialize: initialize,
|
||||
candlesFiles: new Map, // Complete sets of candles for different Time Periods. For Time Periods < 1hs sets are of current day only, otherwise whole market.
|
||||
candlesMap: new Map, // The last 10 candles for each Time Period will be stored here.
|
||||
stairsFiles: new Map, // Complete sets of patterns for different Time Periods. For Time Periods < 1hs sets are of current day only, otherwise whole market.
|
||||
stairsMap: new Map // The patterns we are currently in will be stored here.
|
||||
};
|
||||
|
||||
let bot = BOT;
|
||||
|
||||
const logger = DEBUG_MODULE.newDebugLog();
|
||||
logger.fileName = MODULE_NAME;
|
||||
logger.bot = bot;
|
||||
|
||||
let oliviaStorage = BLOB_STORAGE.newBlobStorage(bot);
|
||||
let tomStorage = BLOB_STORAGE.newBlobStorage(bot);
|
||||
|
||||
/* Utilities needed. */
|
||||
|
||||
let utilities = UTILITIES.newUtilities(bot);
|
||||
|
||||
return thisObject;
|
||||
|
||||
function initialize(callBackFunction) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] initialize -> Entering function."); }
|
||||
|
||||
initializeOliviaStorage();
|
||||
|
||||
function initializeOliviaStorage() {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] initializeOliviaStorage -> Entering function."); }
|
||||
|
||||
oliviaStorage.initialize({ bot: "AAOlivia", devTeam: "AAMasters" }, onInizialized);
|
||||
|
||||
function onInizialized(err) {
|
||||
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
|
||||
initializeTomStorage();
|
||||
} else {
|
||||
logger.write("[ERROR] initialize -> initializeOliviaStorage -> err = " + err.message);
|
||||
callBackFunction(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initializeTomStorage() {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] initializeTomStorage -> Entering function."); }
|
||||
|
||||
tomStorage.initialize({ bot: "AATom", devTeam: "AAMasters" }, onInizialized);
|
||||
|
||||
function onInizialized(err) {
|
||||
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
|
||||
getCandles(onDone);
|
||||
} else {
|
||||
logger.write("[ERROR] initialize -> initializeTomStorage -> err = " + err.message);
|
||||
callBackFunction(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onDone(err) {
|
||||
try {
|
||||
|
||||
switch (err.result) {
|
||||
case global.DEFAULT_OK_RESPONSE.result: {
|
||||
logger.write("[INFO] initialize -> onDone -> Execution finished well. :-)");
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
return;
|
||||
}
|
||||
case global.DEFAULT_RETRY_RESPONSE.result: { // Something bad happened, but if we retry in a while it might go through the next time.
|
||||
logger.write("[ERROR] initialize -> onDone -> Retry Later. Requesting Execution Retry.");
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
|
||||
logger.write("[ERROR] initialize -> onDone -> Operation Failed. Aborting the process.");
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write("[ERROR] initialize -> onDone -> err = " + err.message);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function getCandles(callBack) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] getCandles -> Entering function."); }
|
||||
|
||||
/*
|
||||
|
||||
We will read several files with candles for the current day. We will use these files as an input
|
||||
to make trading decitions later.
|
||||
|
||||
*/
|
||||
|
||||
getMarketFiles();
|
||||
|
||||
function getMarketFiles() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] getCandles -> getMarketFiles -> Entering function."); }
|
||||
|
||||
let filesOk = 0;
|
||||
let filesNotOk = 0;
|
||||
|
||||
for (i = 0; i < global.marketFilesPeriods.length; i++) {
|
||||
|
||||
let periodTime = global.marketFilesPeriods[i][0];
|
||||
let periodName = global.marketFilesPeriods[i][1];
|
||||
|
||||
getFile(oliviaStorage, "@AssetA_@AssetB.json", "@Exchange/Output/Candles/Multi-Period-Market/@Period", periodName, undefined, onFileReceived, callBack);
|
||||
|
||||
function onFileReceived(err, file) {
|
||||
|
||||
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
|
||||
filesOk++;
|
||||
thisObject.candlesFiles.set(periodName, file);
|
||||
} else {
|
||||
filesNotOk++;
|
||||
}
|
||||
|
||||
if (filesOk + filesNotOk === global.marketFilesPeriods.length) {
|
||||
|
||||
if (filesOk === global.marketFilesPeriods.length) {
|
||||
|
||||
getDailyFiles();
|
||||
|
||||
} else {
|
||||
logger.write("[ERROR] getCandles -> getMarketFiles -> onFileReceived -> Some files are missing -> filesNotOk = " + filesNotOk);
|
||||
logger.write("[ERROR] getCandles -> getMarketFiles -> onFileReceived -> Will abort the process and request a retry.");
|
||||
callBack(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write("[ERROR] getCandles -> getMarketFiles -> err = " + err.message);
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function getDailyFiles() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] getCandles -> getDailyFiles -> Entering function."); }
|
||||
|
||||
let filesOk = 0;
|
||||
let filesNotOk = 0;
|
||||
|
||||
for (i = 0; i < global.dailyFilePeriods.length; i++) {
|
||||
|
||||
let periodTime = global.dailyFilePeriods[i][0];
|
||||
let periodName = global.dailyFilePeriods[i][1];
|
||||
|
||||
getFile(oliviaStorage, "@AssetA_@AssetB.json", "@Exchange/Output/Candles/Multi-Period-Daily/@Period/@Year/@Month/@Day", periodName, bot.processDatetime, onFileReceived, callBack);
|
||||
|
||||
function onFileReceived(err, file) {
|
||||
|
||||
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
|
||||
filesOk++;
|
||||
thisObject.candlesFiles.set(periodName, file);
|
||||
} else {
|
||||
filesNotOk++;
|
||||
}
|
||||
|
||||
if (filesOk + filesNotOk === global.dailyFilePeriods.length) {
|
||||
|
||||
if (filesOk === global.dailyFilePeriods.length) {
|
||||
|
||||
getCandlesWeAreIn();
|
||||
|
||||
} else {
|
||||
logger.write("[ERROR] getCandles -> getDailyFiles -> onFileReceived -> Some files are missing -> filesNotOk = " + filesNotOk);
|
||||
logger.write("[ERROR] getCandles -> getDailyFiles -> onFileReceived -> Will abort the process and request a retry.");
|
||||
callBack(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write("[ERROR] getCandles -> getDailyFiles -> err = " + err.message);
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function getCandlesWeAreIn() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] getCandles -> getCandlesWeAreIn -> Entering function."); }
|
||||
|
||||
let counter = 0;
|
||||
|
||||
thisObject.candlesFiles.forEach(getCurrentCandles);
|
||||
|
||||
function getCurrentCandles(pCandlesFile, pPeriodName, map) {
|
||||
|
||||
let candlesArray = [];
|
||||
|
||||
for (i = 0; i < pCandlesFile.length; i++) {
|
||||
|
||||
let candle = {
|
||||
open: undefined,
|
||||
close: undefined,
|
||||
min: 10000000000000,
|
||||
max: 0,
|
||||
begin: undefined,
|
||||
end: undefined,
|
||||
direction: undefined
|
||||
};
|
||||
|
||||
candle.min = pCandlesFile[i][0];
|
||||
candle.max = pCandlesFile[i][1];
|
||||
|
||||
candle.open = pCandlesFile[i][2];
|
||||
candle.close = pCandlesFile[i][3];
|
||||
|
||||
candle.begin = pCandlesFile[i][4];
|
||||
candle.end = pCandlesFile[i][5];
|
||||
|
||||
if (candle.open > candle.close) { candle.direction = 'down'; }
|
||||
if (candle.open < candle.close) { candle.direction = 'up'; }
|
||||
if (candle.open === candle.close) { candle.direction = 'side'; }
|
||||
|
||||
/* We are going to store the last 10 candles per period, which will give the bot a good sense of where it is. */
|
||||
|
||||
let timePeriod = candle.end - candle.begin + 1; // In miliseconds. (remember each candle spans a period minus one milisecond)
|
||||
|
||||
if (candle.begin >= bot.processDatetime.valueOf() - timePeriod * 10 && candle.begin <= bot.processDatetime.valueOf()) {
|
||||
|
||||
candlesArray.push(candle);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
thisObject.candlesMap.set(pPeriodName, candlesArray);
|
||||
|
||||
counter++;
|
||||
|
||||
if (counter === thisObject.candlesFiles.size) {
|
||||
|
||||
getPatterns(callBack);
|
||||
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write("[ERROR] getCandles -> getCandlesWeAreIn -> err = " + err.message);
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write("[ERROR] getCandles -> err = " + err.message);
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function getPatterns(callBack) {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] getPatterns -> Entering function."); }
|
||||
|
||||
/*
|
||||
|
||||
We will read several files with pattern calculations for the current day. We will use these files as an input
|
||||
to make trading decitions later.
|
||||
|
||||
*/
|
||||
|
||||
getMarketFiles();
|
||||
|
||||
function getMarketFiles() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] getPatterns -> getMarketFiles -> Entering function."); }
|
||||
|
||||
let filesOk = 0;
|
||||
let filesNotOk = 0;
|
||||
|
||||
for (i = 0; i < global.marketFilesPeriods.length; i++) {
|
||||
|
||||
let periodTime = global.marketFilesPeriods[i][0];
|
||||
let periodName = global.marketFilesPeriods[i][1];
|
||||
|
||||
getFile(tomStorage, "@AssetA_@AssetB.json", "@Exchange/Tom/dataSet.V1/Output/Candle-Stairs/Multi-Period-Market/@Period", periodName, undefined, onFileReceived, callBack);
|
||||
|
||||
function onFileReceived(err, file) {
|
||||
|
||||
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
|
||||
filesOk++;
|
||||
thisObject.stairsFiles.set(periodName, file);
|
||||
} else {
|
||||
filesNotOk++;
|
||||
}
|
||||
|
||||
if (filesOk + filesNotOk === global.marketFilesPeriods.length) {
|
||||
|
||||
if (filesOk === global.marketFilesPeriods.length) {
|
||||
|
||||
getDailyFiles();
|
||||
|
||||
} else {
|
||||
logger.write("[ERROR] getPatterns -> getMarketFiles -> onFileReceived -> Some files are missing -> filesNotOk = " + filesNotOk);
|
||||
logger.write("[ERROR] getPatterns -> getMarketFiles -> onFileReceived -> Will abort the process and request a retry.");
|
||||
callBack(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write("[ERROR] getPatterns -> getMarketFiles -> err = " + err.message);
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function getDailyFiles() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] getPatterns -> getDailyFiles -> Entering function."); }
|
||||
|
||||
let filesOk = 0;
|
||||
let filesNotOk = 0;
|
||||
|
||||
for (i = 0; i < global.dailyFilePeriods.length; i++) {
|
||||
|
||||
let periodTime = global.dailyFilePeriods[i][0];
|
||||
let periodName = global.dailyFilePeriods[i][1];
|
||||
|
||||
getFile(tomStorage, "@AssetA_@AssetB.json", "@Exchange/Tom/dataSet.V1/Output/Candle-Stairs/Multi-Period-Daily/@Period/@Year/@Month/@Day", periodName, bot.processDatetime, onFileReceived, callBack);
|
||||
|
||||
function onFileReceived(err, file) {
|
||||
|
||||
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
|
||||
filesOk++;
|
||||
thisObject.stairsFiles.set(periodName, file);
|
||||
} else {
|
||||
filesNotOk++;
|
||||
}
|
||||
|
||||
if (filesOk + filesNotOk === global.dailyFilePeriods.length) {
|
||||
|
||||
if (filesOk === global.dailyFilePeriods.length) {
|
||||
|
||||
getStairsWeAreIn();
|
||||
|
||||
} else {
|
||||
logger.write("[ERROR] getPatterns -> getDailyFiles -> onFileReceived -> Some files are missing -> filesNotOk = " + filesNotOk);
|
||||
logger.write("[ERROR] getPatterns -> getDailyFiles -> onFileReceived -> Will abort the process and request a retry.");
|
||||
callBack(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write("[ERROR] getPatterns -> getDailyFiles -> err = " + err.message);
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function getStairsWeAreIn() {
|
||||
|
||||
try {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] getPatterns -> getStairsWeAreIn -> Entering function."); }
|
||||
|
||||
let counter = 0;
|
||||
|
||||
thisObject.stairsFiles.forEach(getCurrentStairs);
|
||||
|
||||
function getCurrentStairs(pStairsFile, pPeriodName, map) {
|
||||
|
||||
for (i = 0; i < pStairsFile.length; i++) {
|
||||
|
||||
let stairs = {
|
||||
open: undefined,
|
||||
close: undefined,
|
||||
min: 10000000000000,
|
||||
max: 0,
|
||||
begin: undefined,
|
||||
end: undefined,
|
||||
direction: undefined,
|
||||
candleCount: 0,
|
||||
firstMin: 0,
|
||||
firstMax: 0,
|
||||
lastMin: 0,
|
||||
lastMax: 0
|
||||
};
|
||||
|
||||
stairs.open = pStairsFile[i][0];
|
||||
stairs.close = pStairsFile[i][1];
|
||||
|
||||
stairs.min = pStairsFile[i][2];
|
||||
stairs.max = pStairsFile[i][3];
|
||||
|
||||
stairs.begin = pStairsFile[i][4];
|
||||
stairs.end = pStairsFile[i][5];
|
||||
|
||||
stairs.direction = pStairsFile[i][6];
|
||||
stairs.candleCount = pStairsFile[i][7];
|
||||
|
||||
stairs.firstMin = pStairsFile[i][8];
|
||||
stairs.firstMax = pStairsFile[i][9];
|
||||
|
||||
stairs.lastMin = pStairsFile[i][10];
|
||||
stairs.lastMax = pStairsFile[i][11];
|
||||
|
||||
if (bot.processDatetime.valueOf() >= stairs.begin && bot.processDatetime.valueOf() <= stairs.end) {
|
||||
|
||||
thisObject.stairsMap.set(pPeriodName, stairs);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
counter++;
|
||||
|
||||
if (counter === thisObject.stairsFiles.size) {
|
||||
|
||||
callBack(global.DEFAULT_OK_RESPONSE);
|
||||
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write("[ERROR] getPatterns -> getStairsWeAreIn -> err = " + err.message);
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write("[ERROR] getPatterns -> err = " + err.message);
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function getFile(pFileStorage, pFileName, pFilePath, pPeriodName, pDatetime, innerCallBack, outerCallBack) {
|
||||
|
||||
try {
|
||||
if (FULL_LOG === true) { logger.write("[INFO] initialize -> getFile -> Entering function."); }
|
||||
if (FULL_LOG === true) { logger.write("[INFO] initialize -> getFile -> pFileName = " + pFileName); }
|
||||
if (FULL_LOG === true) { logger.write("[INFO] initialize -> getFile -> pFilePath = " + pFilePath); }
|
||||
if (FULL_LOG === true) { logger.write("[INFO] initialize -> getFile -> pPeriodName = " + pPeriodName); }
|
||||
if (FULL_LOG === true) { logger.write("[INFO] initialize -> getFile -> pDatetime = " + pDatetime); }
|
||||
|
||||
pFileName = pFileName.replace("@AssetA", MARKET.assetA);
|
||||
pFileName = pFileName.replace("@AssetB", MARKET.assetB);
|
||||
|
||||
pFilePath = pFilePath.replace("@Exchange", global.EXCHANGE_NAME);
|
||||
pFilePath = pFilePath.replace("@Period", pPeriodName);
|
||||
|
||||
if (pDatetime !== undefined) {
|
||||
|
||||
pFilePath = pFilePath.replace("@Year", pDatetime.getUTCFullYear());
|
||||
pFilePath = pFilePath.replace("@Month", utilities.pad(pDatetime.getUTCMonth() + 1, 2));
|
||||
pFilePath = pFilePath.replace("@Day", utilities.pad(pDatetime.getUTCDate(), 2));
|
||||
|
||||
}
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] initialize -> getFile -> final pFilePath = " + pFilePath); }
|
||||
if (FULL_LOG === true) { logger.write("[INFO] initialize -> getFile -> final pFileName = " + pFileName); }
|
||||
|
||||
pFileStorage.getTextFile(pFilePath, pFileName, onFileReceived);
|
||||
|
||||
function onFileReceived(err, text) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] initialize -> getFile -> onFileReceived -> pFilePath = " + pFilePath); }
|
||||
if (FULL_LOG === true) { logger.write("[INFO] initialize -> getFile -> onFileReceived -> pFileName = " + pFileName); }
|
||||
|
||||
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
|
||||
logger.write("[ERROR] initialize -> getFile -> onFileReceived -> err = " + err.message);
|
||||
innerCallBack(err);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
let data = JSON.parse(text);
|
||||
innerCallBack(global.DEFAULT_OK_RESPONSE, data);
|
||||
|
||||
} catch (err) {
|
||||
logger.write("[ERROR] initialize -> getFile -> onFileReceived -> Parsing JSON -> err = " + err.message);
|
||||
innerCallBack(err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write("[ERROR] initialize -> getFile -> err = " + err.message);
|
||||
outerCallBack("Operation Failed");
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
|
||||
logger.write("[ERROR] initialize -> err = " + err.message);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -42,9 +42,6 @@
|
||||
<Compile Include="Context.js">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Datasource.js">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Debug Log.js" />
|
||||
<Compile Include="ExchangeAPI.js">
|
||||
<SubType>Code</SubType>
|
||||
|
||||
@@ -298,9 +298,8 @@ for (let p = 0; p < global.PLATFORM_CONFIG.executionList.length; p++) {
|
||||
runIndicatorBot(botConfig, processConfig, month, year);
|
||||
break;
|
||||
}
|
||||
case 'Trading': {
|
||||
runTradingBot(botConfig, processConfig);
|
||||
break;
|
||||
default: {
|
||||
logger.write("[ERROR] run -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,23 +320,23 @@ for (let p = 0; p < global.PLATFORM_CONFIG.executionList.length; p++) {
|
||||
runExtractionBot(botConfig, processConfig, month, year);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
logger.write("[ERROR] run -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (processConfig.startMode.timePeriod !== undefined) {
|
||||
if (processConfig.startMode.live !== undefined) {
|
||||
|
||||
if (processConfig.startMode.timePeriod.run === "true") {
|
||||
if (processConfig.startMode.live.run === "true") {
|
||||
|
||||
botConfig.backTestingMode = true;
|
||||
botConfig.timePeriod = processConfig.startMode.timePeriod;
|
||||
botConfig.runMode = "Live";
|
||||
|
||||
/* We override these waitTimes to the one specified at the timePeriod configuration. */
|
||||
let month = pad((new Date()).getUTCMonth() + 1, 2);
|
||||
let year = (new Date()).getUTCFullYear();
|
||||
|
||||
processConfig.normalWaitTime = processConfig.startMode.timePeriod.waitTime;
|
||||
processConfig.retryWaitTime = processConfig.startMode.timePeriod.waitTime;
|
||||
|
||||
if (processConfig.startMode.timePeriod.resumeExecution === "true") {
|
||||
if (processConfig.startMode.live.resumeExecution === "true") {
|
||||
botConfig.hasTheBotJustStarted = false;
|
||||
} else {
|
||||
botConfig.hasTheBotJustStarted = true;
|
||||
@@ -348,6 +347,62 @@ for (let p = 0; p < global.PLATFORM_CONFIG.executionList.length; p++) {
|
||||
runTradingBot(botConfig, processConfig);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
logger.write("[ERROR] run -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (processConfig.startMode.backtest !== undefined) {
|
||||
|
||||
if (processConfig.startMode.backtest.run === "true") {
|
||||
|
||||
botConfig.runMode = "Backtest";
|
||||
botConfig.backtest = processConfig.startMode.backtest;
|
||||
|
||||
/* We override these waitTimes to the one specified at the backtest configuration. */
|
||||
|
||||
processConfig.normalWaitTime = processConfig.startMode.backtest.waitTime;
|
||||
processConfig.retryWaitTime = processConfig.startMode.backtest.waitTime;
|
||||
|
||||
/* Backtest Mode does not support Resume Execution, so this is the only way. */
|
||||
|
||||
botConfig.hasTheBotJustStarted = true;
|
||||
|
||||
switch (botConfig.type) {
|
||||
case 'Trading': {
|
||||
runTradingBot(botConfig, processConfig);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
logger.write("[ERROR] run -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (processConfig.startMode.competition !== undefined) {
|
||||
|
||||
if (processConfig.startMode.competition.run === "true") {
|
||||
|
||||
botConfig.runMode = "Competition";
|
||||
botConfig.competition = processConfig.startMode.competition;
|
||||
|
||||
if (processConfig.startMode.competition.resumeExecution === "true") {
|
||||
botConfig.hasTheBotJustStarted = false;
|
||||
} else {
|
||||
botConfig.hasTheBotJustStarted = true;
|
||||
}
|
||||
|
||||
switch (botConfig.type) {
|
||||
case 'Trading': {
|
||||
runTradingBot(botConfig, processConfig);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
logger.write("[ERROR] run -> Unexpected bot type. -> botConfig.type = " + botConfig.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,6 @@
|
||||
const POLONIEX_CLIENT_MODULE = require(ROOT_DIR + 'Poloniex API Client');
|
||||
const EXCHANGE_API = require(ROOT_DIR + 'ExchangeAPI');
|
||||
const CONTEXT = require(ROOT_DIR + 'Context');
|
||||
const DATASOURCE = require(ROOT_DIR + 'Datasource');
|
||||
const ASSISTANT = require(ROOT_DIR + 'Assistant');
|
||||
const STATUS_REPORT = require(ROOT_DIR + 'Status Report');
|
||||
const DATA_SET = require(ROOT_DIR + 'Data Set');
|
||||
@@ -77,48 +76,83 @@
|
||||
|
||||
/* 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. */
|
||||
|
||||
if (bot.backTestingMode === true) {
|
||||
switch (bot.runMode) {
|
||||
case 'Live': {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> Backtesting Mode detected."); }
|
||||
if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> Live Mode detected."); }
|
||||
|
||||
if (bot.hasTheBotJustStarted === true) {
|
||||
// This will be considered the process date and time, so as to have it consistenly all over the execution.
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> Bot just starting, setting initial datetime."); }
|
||||
let localDate = new Date();
|
||||
|
||||
bot.processDatetime = new Date(bot.timePeriod.beginDatetime); // Set the starting time as the configured beginDatetime.
|
||||
|
||||
} else {
|
||||
|
||||
bot.processDatetime = new Date(bot.processDatetime.valueOf() + 60000); // We advance one minute in time.
|
||||
|
||||
let endDatetime = new Date(bot.timePeriod.endDatetime);
|
||||
|
||||
if (bot.processDatetime.valueOf() > endDatetime.valueOf()) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> End of Backtesting Period reached. Exiting Bot Process Loop."); }
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
return;
|
||||
}
|
||||
bot.processDatetime = new Date(Date.UTC(
|
||||
localDate.getUTCFullYear(),
|
||||
localDate.getUTCMonth(),
|
||||
localDate.getUTCDate(),
|
||||
localDate.getUTCHours(),
|
||||
localDate.getUTCMinutes(),
|
||||
localDate.getUTCSeconds(),
|
||||
localDate.getUTCMilliseconds()));
|
||||
break;
|
||||
}
|
||||
case 'Backtest': {
|
||||
|
||||
} else { // We are running Live!
|
||||
if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> Backtesting Mode detected."); }
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> Live Mode detected."); }
|
||||
if (bot.hasTheBotJustStarted === true) {
|
||||
|
||||
// This will be considered the process date and time, so as to have it consistenly all over the execution.
|
||||
if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> Bot just starting, setting initial datetime."); }
|
||||
|
||||
let localDate = new Date();
|
||||
bot.processDatetime = new Date(bot.backtest.beginDatetime); // Set the starting time as the configured beginDatetime.
|
||||
|
||||
bot.processDatetime = new Date(Date.UTC(
|
||||
localDate.getUTCFullYear(),
|
||||
localDate.getUTCMonth(),
|
||||
localDate.getUTCDate(),
|
||||
localDate.getUTCHours(),
|
||||
localDate.getUTCMinutes(),
|
||||
localDate.getUTCSeconds(),
|
||||
localDate.getUTCMilliseconds()));
|
||||
} else {
|
||||
|
||||
bot.processDatetime = new Date(bot.processDatetime.valueOf() + 60000); // We advance one minute in time.
|
||||
|
||||
let endDatetime = new Date(bot.backtest.endDatetime);
|
||||
|
||||
if (bot.processDatetime.valueOf() > endDatetime.valueOf()) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> End of Backtesting Period reached. Exiting Bot Process Loop."); }
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'Competition': {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> Competition Mode detected."); }
|
||||
|
||||
if (bot.hasTheBotJustStarted === true) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> Bot just starting, setting initial datetime."); }
|
||||
|
||||
bot.processDatetime = new Date(bot.competition.beginDatetime); // Set the starting time as the configured beginDatetime.
|
||||
|
||||
} else {
|
||||
|
||||
bot.processDatetime = new Date(bot.processDatetime.valueOf() + 60000); // We advance one minute in time.
|
||||
|
||||
let endDatetime = new Date(bot.competition.endDatetime);
|
||||
|
||||
if (bot.processDatetime.valueOf() > endDatetime.valueOf()) {
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> End of Competition Period reached. Exiting Bot Process Loop."); }
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
logger.write("[ERROR] run -> loop -> Unexpected bot.runMode.");
|
||||
logger.write("[ERROR] run -> loop -> bot.runMode = " + bot.runMode);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> bot.processDatetime = " + bot.processDatetime); }
|
||||
|
||||
Reference in new issue
Block a user