diff --git a/.vs/AACloudPlatform/v15/.suo b/.vs/AACloudPlatform/v15/.suo index 6883bb021..b38028a8a 100644 Binary files a/.vs/AACloudPlatform/v15/.suo and b/.vs/AACloudPlatform/v15/.suo differ diff --git a/Assistant.js b/Assistant.js index e50224ebf..aa9ffe674 100644 --- a/Assistant.js +++ b/Assistant.js @@ -18,7 +18,8 @@ getBalance: getBalance, getAvailableBalance: getAvailableBalance, getInvestment: getInvestment, - getProfits: getProfits + getProfits: getProfits, + getMarketRate: getMarketRate }; let bot = BOT; @@ -32,10 +33,13 @@ let context; let exchangeAPI; + let datasource; + + let marketRate; return thisObject; - function initialize(pContext, pExchangeAPI, callBackFunction) { + function initialize(pContext, pExchangeAPI, pDatasource, callBackFunction) { try { @@ -45,6 +49,28 @@ context = pContext; exchangeAPI = pExchangeAPI; + datasource = pDatasource; + + /* Procedure to get the current market rate. */ + + let candleArray = datasource.candlesMap.get("01-min"); // In this version of the platform, this array will contain the las 10 candles. + let candle = candleArray[candleArray.length - 1]; // The last candle of the 10 candles array for the 1 min Time Period. + + let 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 < global.processDatetime.valueOf() - 2 * 60 * 1000) { + + logger.write("[ERROR] initialize -> Candles more than two minutes old. Retrying later."); + callBack(global.DEFAULT_RETRY_RESPONSE); + return; + } + + /* Procedure to validate we are in sync with the exchange. */ getPositionsAtExchange(onDone); @@ -432,6 +458,8 @@ 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]); @@ -468,6 +496,28 @@ 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) { @@ -754,4 +804,8 @@ function getProfits() { return JSON.parse(JSON.stringify(context.executionContext.profits)); } + + function getMarketRate() { + return thisObject.marketRate; + } }; \ No newline at end of file diff --git a/Context.js b/Context.js index 6902c5669..fb5d787c5 100644 --- a/Context.js +++ b/Context.js @@ -40,13 +40,14 @@ date: undefined, buyAvgRate: 0, sellAvgRate: 0, + marketRate: 0, newPositions: 0, newTrades: 0, movedPositions: 0, profitsAssetA: 0, profitsAssetB: 0, - profitsCombinedInA: 0, - profitsCombinedInB: 0 + combinedProfitsA: 0, + combinedProfitsB: 0 }, initialize: initialize, saveThemAll: saveThemAll @@ -226,6 +227,12 @@ try { thisObject.executionHistory = JSON.parse(text); + + /* Move some values to the new record, in case there are no transactions that re-calculate them. */ + + thisObject.newHistoryRecord.buyAvgRate = thisObject.executionHistory[1]; + thisObject.newHistoryRecord.sellAvgRate = thisObject.executionHistory[2]; + getExecutionContext(callBack); } catch (err) { @@ -282,6 +289,15 @@ thisObject.executionContext = JSON.parse(text); thisObject.executionContext.transactions = []; // We record here the transactions that happened duting this execution. + + /* Update the new History Record, in case there are no trades during this execution that updates it. */ + + thisObject.newHistoryRecord.profitsAssetA = thisObject.executionContext.profits.assetA; + thisObject.newHistoryRecord.profitsAssetB = thisObject.executionContext.profits.assetB; + + thisObject.newHistoryRecord.combinedProfitsA = thisObject.executionContext.combinedProfits.assetA; + thisObject.newHistoryRecord.combinedProfitsB = thisObject.executionContext.combinedProfits.assetB; + callBack(global.DEFAULT_OK_RESPONSE); } catch (err) { @@ -312,7 +328,7 @@ /* When the bot is executed for the very first time, there are a few files that do not exist and need to be created, and that - is what we are going to do now. + content is what we are going to set up now. */ @@ -320,24 +336,34 @@ thisObject.executionHistory = []; + /* + In the current release, the platform is going to be used for the first competition, so we have a few parameters just for that. They will be removed later + once we advance into multiple competitions scheme. + */ + + const INITIAL_INVESTMENT = 0.0001; // This is just for this release of the platform. + thisObject.executionContext = { investment: { // This is used to calculate profits. assetA: 0, - assetB: global.INITIAL_INVESTMENT + assetB: INITIAL_INVESTMENT }, balance: { // This is the total balance that includes positions at the order book + funds available to be traded. assetA: 0, - assetB: global.INITIAL_INVESTMENT // It starts with the initial investment. + assetB: INITIAL_INVESTMENT // It starts with the initial investment. }, availableBalance: { // This is the balance the bot has at any moment in time available to be traded (not in positions at the order book). assetA: 0, - assetB: global.INITIAL_INVESTMENT // It starts with the initial investment. + assetB: INITIAL_INVESTMENT // It starts with the initial investment. }, - profitsAsset: global.PROFIT_BASE_ASSET, profits: { assetA: 0, assetB: 0 }, + combinedProfits: { + assetA: 0, + assetB: 0 + }, positions: [], transactions: [] }; @@ -489,8 +515,8 @@ thisObject.newHistoryRecord.movedPositions, thisObject.newHistoryRecord.profitsAssetA, thisObject.newHistoryRecord.profitsAssetB, - thisObject.newHistoryRecord.profitsCombinedInA, - thisObject.newHistoryRecord.profitsCombinedInB + thisObject.newHistoryRecord.combinedProfitsA, + thisObject.newHistoryRecord.combinedProfitsB ]; thisObject.executionHistory.push(newRecord); diff --git a/Run.js b/Run.js index 27a98fa55..76c1b44eb 100644 --- a/Run.js +++ b/Run.js @@ -127,14 +127,6 @@ global.dailyFilePeriods = global.dailyFilePeriods = JSON.parse(global.dailyFilePeriods); -/* -In the current release, the platform is going to be used for the first competition, so we have a few parameters just for that. They will be removed later -once we advance into multiple competitions scheme. -*/ - -global.INITIAL_INVESTMENT = 0.0001; -global.PROFIT_BASE_ASSET = 'BTC'; - /* Some LAGACY code starts here. Pending for clean up. */ diff --git a/Trading Bot Main Loop.js b/Trading Bot Main Loop.js index 0a6b6200d..10b5840e3 100644 --- a/Trading Bot Main Loop.js +++ b/Trading Bot Main Loop.js @@ -182,7 +182,7 @@ if (FULL_LOG === true) { logger.write("[INFO] run -> loop -> initializeAssistant -> Entering function."); } assistant = ASSISTANT.newAssistant(bot, DEBUG_MODULE); - assistant.initialize(context, exchangeAPI, onInizialized); + assistant.initialize(context, exchangeAPI, datasource, onInizialized); function onInizialized(err) {