Backtest Mode Running

This commit is contained in:
Luis Fernando Molina committed 2018-04-25 20:09:51 +02:00
1 parent 2ff60c4b4c
commit 449ce20445
6 files changed
+311 -194

No files matched your search

Binary file not shown.
+263 -165
View File
@@ -1,4 +1,4 @@
exports.newAssistant = function newAssistant(BOT, DEBUG_MODULE) {
exports.newAssistant = function newAssistant(BOT, DEBUG_MODULE, UTILITIES) {
const FULL_LOG = true;
const LOG_FILE_CONTENT = false;
@@ -30,6 +30,8 @@
logger.fileName = MODULE_NAME;
logger.bot = bot;
let utilities = UTILITIES.newUtilities(bot);
let exchangePositions = []; // These are the open positions at the exchange at the account the bot is authorized to use.
let openPositions = []; // These are the open positions the bot knows it made by itself.
@@ -72,8 +74,9 @@
let dataSet = thisObject.dataDependencies.dataSets.get(key);
let timePeriod = "01-min";
let dateForPath = bot.processDatetime.getUTCFullYear() + '/' + utilities.pad(bot.processDatetime.getUTCMonth() + 1, 2) + '/' + utilities.pad(bot.processDatetime.getUTCDate(), 2);
let fileName = '' + global.MARKET.assetA + '_' + global.MARKET.assetB + '.json';
let filePath = global.PLATFORM_CONFIG.marketRateProvider.product + "/" + global.PLATFORM_CONFIG.marketRateProvider.dataSet + "/" + timePeriod;
let filePath = global.PLATFORM_CONFIG.marketRateProvider.product + "/" + global.PLATFORM_CONFIG.marketRateProvider.dataSet + "/" + timePeriod + "/" + dateForPath;
dataSet.getTextFile(filePath, fileName, onFileReceived, true);
@@ -88,46 +91,73 @@
try {
candleArray = JSON.parse(text);
let lastCandleRecord = candleArray[candleArray.length - 1]; // The last candle contains at its close value the market rate.
if (bot.backTestingMode === true) {
let candle = {
open: lastCandleRecord[2],
close: lastCandleRecord[3],
min: lastCandleRecord[0],
max: lastCandleRecord[1],
begin: lastCandleRecord[4],
end: lastCandleRecord[5]
};
logger.write("[INFO] initialize -> getMarketRate -> onFileReceived -> Backtest Mode detected.");
marketRate = candle.close;
/* We need to find the candle at which the process is currently running. */
/*
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.
*/
for (let i = 0; i < candleArray.length; i++) {
if (candle.begin < bot.processDatetime.valueOf() - 2 * 60 * 1000) {
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]
};
logger.write("[ERROR] initialize -> Candles more than two minutes old. Retrying later.");
callBack(global.DEFAULT_RETRY_RESPONSE);
return;
}
if (bot.processDatetime.valueOf() >= candle.begin && bot.processDatetime.valueOf() < candle.end) {
/* If we are in Exchange Simulation Mode then there is not much to do here. */
marketRate = (candle.open + candle.close) / 2;
if (bot.backTesting === true) {
/* 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. */
logger.write("[WARN] initialize -> Backtesting Mode detected. -> Skipping validateExchangeSyncronicity.");
callBackFunction(global.DEFAULT_OK_RESPONSE);
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;
} else {
} 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;
/*
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.
*/
if (candle.begin < bot.processDatetime.valueOf() - 2 * 60 * 1000) {
logger.write("[ERROR] initialize -> Candles more than two minutes old. Retrying later.");
callBack(global.DEFAULT_RETRY_RESPONSE);
return;
}
validateExchangeSyncronicity();
return;
}
} catch (err) {
logger.write("[ERROR] initialize -> getMarketRate -> onFileReceived -> err = " + err.message);
logger.write("[ERROR] initialize -> getMarketRate -> onFileReceived -> Asuming this is a temporary situation. Requesting a Retry.");
@@ -211,7 +241,19 @@
*/
exchangeAPI.getOpenPositions(global.MARKET, onResponse);
if (bot.backTestingMode === true) {
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);
} else {
if (FULL_LOG === true) { logger.write("[INFO] getPositionsAtExchange -> Live Mode Detected."); }
exchangeAPI.getOpenPositions(global.MARKET, onResponse);
}
function onResponse(err, pExchangePositions) {
@@ -390,75 +432,6 @@
}
}
}
function confirmOrderWasExecuted(pTrades) {
try {
if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> Entering function."); }
if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> pTrades = " + JSON.stringify(pTrades)); }
/*
To confirm everything is ok, we will add all the amounts on trades asociated to the order and
they must be equal to the one on file. Otherwise something very strange could have happened,
in which case we will halt the bot execution.
*/
let sumAssetA = 0;
let sumAssetB = 0;
for (let k = 0; k < pTrades.length; k++) {
sumAssetA = sumAssetA + pTrades[k].amountA;
sumAssetB = sumAssetB + pTrades[k].amountB;
}
/* We add the fees */
sumAssetA = sumAssetA + exchangePositions[j].fee;
if (
position.amountA !== sumAssetA ||
position.amountB !== sumAssetB
) {
logger.write("[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> Cannot be confirmed that the order was executed. It must be manually cancelled by the user or cancelled by the exchange itself.");
logger.write("[HINT] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> Verify also that you were not running under a Exchange Simulation and you turned it off without deleting the Status Report file.");
logger.write("[HINT] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> If the process was abruptally cancelled and then restarted, it is possible that now is not sincronized with the exchange.");
logger.write("[HINT] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> In any case, to continue, you must delete the Status Report file so as to start over. Also, you must manually delete the orders at the exchange.");
callBack(global.DEFAULT_FAIL_RESPONSE);
return;
}
/*
Confirmed that order was executed. Next thing to do is to remember the trades and change its status.
*/
position.status = "executed";
applyTradesToContext(pTrades);
let newTransaction = {
type: position.type + " executed",
position: position
};
context.executionContext.transactions.push(newTransaction);
/* All done. */
next();
} catch (err) {
logger.write("[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
return;
}
}
}
/* Position not found: we need to know if the order was executed. */
@@ -478,8 +451,49 @@
*/
exchangeAPI.getExecutedTrades(pPositionId, onResponse);
if (bot.backTestingMode === true) {
if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> Backtest Mode Detected."); }
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 -> getPositionTradesAtExchange -> Position not found at Executioin Context.");
callBack(global.DEFAULT_FAIL_RESPONSE);
return;
} else {
if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> getPositionTradesAtExchange -> Live Mode Detected."); }
exchangeAPI.getExecutedTrades(pPositionId, onResponse);
}
function onResponse(err, pTrades) {
try {
@@ -513,7 +527,150 @@
}
}
function confirmOrderWasExecuted(pTrades) {
try {
if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> Entering function."); }
if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> pTrades = " + JSON.stringify(pTrades)); }
/*
To confirm everything is ok, we will add all the amounts on trades asociated to the order and
they must be equal to the one on file. Otherwise something very strange could have happened,
in which case we will halt the bot execution.
*/
let sumAssetA = 0;
let sumAssetB = 0;
for (let k = 0; k < pTrades.length; k++) {
sumAssetA = sumAssetA + pTrades[k].amountA;
sumAssetB = sumAssetB + pTrades[k].amountB;
}
/* We add the fees */
//sumAssetA = sumAssetA + exchangePositions[j].fee;
if (
position.amountA !== sumAssetA ||
position.amountB !== sumAssetB
) {
logger.write("[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> Cannot be confirmed that the order was executed. It must be manually cancelled by the user or cancelled by the exchange itself.");
logger.write("[HINT] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> Verify also that you were not running under a Exchange Simulation and you turned it off without deleting the Status Report file.");
logger.write("[HINT] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> If the process was abruptally cancelled and then restarted, it is possible that now is not sincronized with the exchange.");
logger.write("[HINT] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> In any case, to continue, you must delete the Status Report file so as to start over. Also, you must manually delete the orders at the exchange.");
callBack(global.DEFAULT_FAIL_RESPONSE);
return;
}
/*
Confirmed that order was executed. Next thing to do is to remember the trades and change its status.
*/
position.status = "executed";
applyTradesToContext(pTrades);
let newTransaction = {
type: position.type + " executed",
position: position
};
context.executionContext.transactions.push(newTransaction);
/* All done. */
next();
} catch (err) {
logger.write("[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
return;
}
}
function applyTradesToContext(pTrades) {
try {
if (FULL_LOG === true) { logger.write("[INFO] ordersExecutionCheck -> loopBody -> applyTradesToContext -> Entering function."); }
/* Here we apply the trades that already happened at the exchange to the balance and available balance of the bot. We also calculate its profits. */
for (k = 0; k < pTrades.length; k++) {
let trade = pTrades[k];
position.trades.push(trade);
context.newHistoryRecord.newTrades++;
/* Calculate Balances */
if (trade.type === 'buy') {
context.executionContext.balance.assetA = context.executionContext.balance.assetA - trade.amountA;
context.executionContext.balance.assetB = context.executionContext.balance.assetB + trade.amountB;
context.executionContext.availableBalance.assetB = context.executionContext.availableBalance.assetB + trade.amountB;
}
if (trade.type === 'sell') {
context.executionContext.balance.assetA = context.executionContext.balance.assetA + trade.amountA;
context.executionContext.balance.assetB = context.executionContext.balance.assetB - trade.amountB;
context.executionContext.availableBalance.assetA = context.executionContext.availableBalance.assetA + trade.amountA;
}
}
/* Calculate Profits */
if (context.executionContext.investment.assetA > 0) {
context.executionContext.profits.assetA = (context.executionContext.balance.assetA - context.executionContext.investment.assetA) / context.executionContext.investment.assetA;
}
if (context.executionContext.investment.assetB > 0) {
context.executionContext.profits.assetB = (context.executionContext.balance.assetB - context.executionContext.investment.assetB) / context.executionContext.investment.assetB;
}
context.newHistoryRecord.profitsAssetA = context.executionContext.profits.assetA;
context.newHistoryRecord.profitsAssetB = context.executionContext.profits.assetB;
/* Calculate Combined Profits */
if (context.executionContext.investment.assetA > 0) {
let convertedAssetsB = (context.executionContext.balance.assetB - context.executionContext.investment.assetB) / marketRate;
context.executionContext.combinedProfits.assetA = (context.executionContext.balance.assetA + convertedAssetsB - context.executionContext.investment.assetA) / context.executionContext.investment.assetA;
}
if (context.executionContext.investment.assetB > 0) {
let convertedAssetsA = (context.executionContext.balance.assetA - context.executionContext.investment.assetA) * marketRate;
context.executionContext.combinedProfits.assetB = (context.executionContext.balance.assetB + convertedAssetsA - context.executionContext.investment.assetB) / context.executionContext.investment.assetB;
}
context.newHistoryRecord.combinedProfitsA = context.executionContext.combinedProfits.assetA;
context.newHistoryRecord.combinedProfitsB = context.executionContext.combinedProfits.assetB;
} catch (err) {
logger.write("[ERROR] ordersExecutionCheck -> loopBody -> applyTradesToContext -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
return;
}
}
} catch (err) {
logger.write("[ERROR] ordersExecutionCheck -> loopBody -> err = " + err.message);
@@ -548,70 +705,6 @@
}
function applyTradesToContext(pTrades) {
/* Here we apply the trades that already happened at the exchange to the balance and available balance of the bot. We also calculate its profits. */
for (k = 0; k < pTrades.length; k++) {
position.pTrades.push(pTrades[k]);
context.newHistoryRecord.newTrades++;
/* Calculate Balances */
if (trade.type === 'buy') {
context.executionContext.balance.assetA = context.executionContext.balance.assetA - trade.amountA;
context.executionContext.balance.assetB = context.executionContext.balance.assetB + trade.amountB;
context.executionContext.availableBalance.assetB = context.executionContext.availableBalance.assetB + trade.amountB;
}
if (trade.type === 'sell') {
context.executionContext.balance.assetA = context.executionContext.balance.assetA + trade.amountA;
context.executionContext.balance.assetB = context.executionContext.balance.assetB - trade.amountB;
context.executionContext.availableBalance.assetA = context.executionContext.availableBalance.assetA + trade.amountA;
}
}
/* Calculate Profits */
if (context.executionContext.investment.assetA > 0) {
context.executionContext.profits.assetA = (context.executionContext.balance.assetA - context.executionContext.investment.assetA) / context.executionContext.investment.assetA;
}
if (context.executionContext.investment.assetB > 0) {
context.executionContext.profits.assetB = (context.executionContext.balance.assetB - context.executionContext.investment.assetB) / context.executionContext.investment.assetB;
}
context.newHistoryRecord.profitsAssetA = context.executionContext.profits.assetA;
context.newHistoryRecord.profitsAssetB = context.executionContext.profits.assetB;
/* Calculate Combined Profits */
if (context.executionContext.investment.assetA > 0) {
let convertedAssetsB = (context.executionContext.balance.assetB - context.executionContext.investment.assetB) / marketRate;
context.executionContext.combinedProfits.assetA = (context.executionContext.balance.assetA + convertedAssetsB - context.executionContext.investment.assetA) / context.executionContext.investment.assetA;
}
if (context.executionContext.investment.assetB > 0) {
let convertedAssetsA = (context.executionContext.balance.assetA - context.executionContext.investment.assetA) * marketRate;
context.executionContext.combinedProfits.assetB = (context.executionContext.balance.assetB + convertedAssetsA - context.executionContext.investment.assetB) / context.executionContext.investment.assetB;
}
context.newHistoryRecord.combinedProfitsA = context.executionContext.combinedProfits.assetA;
context.newHistoryRecord.combinedProfitsB = context.executionContext.combinedProfits.assetB;
}
} catch (err) {
logger.write("[ERROR] ordersExecutionCheck -> err = " + err.message);
callBack(global.DEFAULT_FAIL_RESPONSE);
@@ -683,7 +776,13 @@
/* All validations passed, we proceed. */
if (bot.backTesting === true) {
if (bot.backTestingMode === true) {
if (pRate !== marketRate) {
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); }
@@ -776,7 +875,7 @@
if (FULL_LOG === true) { logger.write("[INFO] movePosition -> pPosition = " + JSON.stringify(pPosition)); }
if (FULL_LOG === true) { logger.write("[INFO] movePosition -> pNewRate = " + pNewRate); }
if (bot.backTesting === true) {
if (bot.backTestingMode === true) {
let positionId = Math.trunc(Math.random(1) * 1000000);
if (FULL_LOG === true) { logger.write("[INFO] putPosition -> Simulating Exchange Response -> orderId = " + positionId); }
@@ -896,7 +995,6 @@
context.newHistoryRecord.sellAvgRate = (sumSellWeightedRates / sumSellWeights || 0);
}
function getPositions() {
return JSON.parse(JSON.stringify(context.executionContext.positions));
}
+37 -18
View File
@@ -240,7 +240,23 @@
if (FULL_LOG === true) { logger.write("[INFO] initialize -> getExecutionContext -> Entering function."); }
let date = new Date(thisObject.statusReport.lastExecution);
let date;
let runType = thisObject.statusReport.runType;
switch (runType) {
case "Backtest": {
date = new Date(thisObject.statusReport.backtestRuns[thisObject.statusReport.runIndex].lastExecution);
thisObject.statusReport.backtestRuns[thisObject.statusReport.runIndex].lastExecution = bot.processDatetime;
break;
}
case "Live": {
date = new Date(thisObject.statusReport.liveRuns[thisObject.statusReport.runIndex].lastExecution);
thisObject.statusReport.liveRuns[thisObject.statusReport.runIndex].lastExecution = bot.processDatetime;
break;
}
}
let fileName = "Execution.Context." + thisObject.statusReport.runType + "." + thisObject.statusReport.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);
@@ -312,7 +328,7 @@
let runType;
if (bot.backTesting === true) {
if (bot.backTestingMode === true) {
runType = "Backtest";
} else {
runType = "Live";
@@ -329,26 +345,28 @@
backtestRuns: []
};
} else { // The Status Report does exist, we just need to move to the next runIndex.
}
thisObject.statusReport.runType = runType;
let runContent = {
lastExecution: bot.processDatetime
};
let runContent = {
beginDatetime: (new Date(bot.timePeriod.beginDatetime)).valueOf(),
endDatetime: (new Date(bot.timePeriod.endDatetime)).valueOf(),
lastExecution: bot.processDatetime
};
switch (runType) {
thisObject.statusReport.runType = runType;
case "Backtest": {
thisObject.statusReport.backtestRuns.push(runContent);
thisObject.statusReport.runIndex = thisObject.statusReport.backtestRuns.lenght - 1;
break;
}
switch (runType) {
case "Live": {
thisObject.statusReport.liveRuns.push(runContent);
thisObject.statusReport.runIndex = thisObject.statusReport.liveRuns.lenght - 1;
break;
}
case "Backtest": {
thisObject.statusReport.backtestRuns.push(runContent);
thisObject.statusReport.runIndex = thisObject.statusReport.backtestRuns.length - 1;
break;
}
case "Live": {
thisObject.statusReport.liveRuns.push(runContent);
thisObject.statusReport.runIndex = thisObject.statusReport.liveRuns.length - 1;
break;
}
}
@@ -579,6 +597,7 @@
if (FULL_LOG === true) { logger.write("[INFO] saveThemAll -> writeStatusReport -> Entering function."); }
statusReportModule.file = thisObject.statusReport;
statusReportModule.save(callBack);
}
+1 -1
View File
@@ -323,7 +323,7 @@ for (let p = 0; p < global.PLATFORM_CONFIG.executionList.length; p++) {
if (processConfig.startMode.timePeriod.run === "true") {
botConfig.backTesting = true;
botConfig.backTestingMode = true;
botConfig.hasTheBotJustStarted = true;
botConfig.timePeriod = processConfig.startMode.timePeriod;
+8 -8
View File
@@ -66,7 +66,7 @@
const BLOB_STORAGE = require(ROOT_DIR + 'Blob Storage');
const DEBUG_MODULE = require(ROOT_DIR + 'Debug Log');
const POLONIEX_CLIENT_MODULE = require(ROOT_DIR + 'Poloniex API Client');
const EXCHANGE_API = require(ROOT_DIR + 'RealExchangeAPI');
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');
@@ -77,7 +77,7 @@
/* 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.backTesting === true) {
if (bot.backTestingMode === true) {
if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> Backtesting Mode detected."); }
@@ -87,7 +87,11 @@
bot.processDatetime = new Date(bot.timePeriod.beginDatetime); // Set the starting time as the configured beginDatetime.
let endDatetime = new Date(bot.timePeriod.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()) {
@@ -96,10 +100,6 @@
callBackFunction(global.DEFAULT_OK_RESPONSE);
return;
}
} else {
bot.processDatetime = new Date(bot.processDatetime.valueOf() + 60000); // We advance one minute in time.
}
} else { // We are running Live!
@@ -280,7 +280,7 @@
if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> initializeAssistant -> Entering function."); }
assistant = ASSISTANT.newAssistant(bot, DEBUG_MODULE);
assistant = ASSISTANT.newAssistant(bot, DEBUG_MODULE, UTILITIES);
assistant.initialize(context, exchangeAPI, dataDependencies, onInizialized);
function onInizialized(err) {
+2 -2
View File
@@ -7,7 +7,7 @@
},
"executionList": [
{
"enabled": "false",
"enabled": "true",
"botPath": "../Bots/AAMasters/AAMariam-Trading-Bot",
"process": "Trading-Process"
},
@@ -32,7 +32,7 @@
"process": "Poloniex-Hole-Fixing"
},
{
"enabled": "true",
"enabled": "false",
"botPath": "../Bots/AAMasters/AACharly-Extraction-Bot",
"process": "Poloniex-Live-Trades"
},