From 990a0b1eaf86f465569996b37f608048591e5ea9 Mon Sep 17 00:00:00 2001 From: matbenitez <34651529+matbenitez@users.noreply.github.com> Date: Sun, 6 May 2018 13:50:33 -0300 Subject: [PATCH 1/3] Simulation changes plus context calculations. Assistant: Adding the fee on backtesting. Recalculations based on fee behavior of the exchange. Context: Adding common parameter for initial context assignment. Poloniex API Client: Adding a new known issue to retry when the exchange call fails on server side. --- Assistant.js | 172 ++++++++++++++++++++--------------------- Context.js | 15 ++-- Poloniex API Client.js | 3 +- 3 files changed, 96 insertions(+), 94 deletions(-) diff --git a/Assistant.js b/Assistant.js index cc5fd54b0..aa24858ee 100644 --- a/Assistant.js +++ b/Assistant.js @@ -516,17 +516,22 @@ 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() - } - + + let feeRate = 0.0025; // Default fee + + if (Math.random(1) < 0.5) + feeRate = 0.0015; // Some times we will pay less fee + + let trade = { + id: Math.trunc(Math.random(1) * 1000000), + type: thisPosition.type, + rate: thisPosition.rate.toString(), + amountA: Number(thisPosition.amountA.toFixed(8)).toString(), + amountB: Number(thisPosition.amountB.toFixed(8)).toString(), + fee: Number(feeRate.toFixed(8)).toString(), + date: (new Date()).valueOf() + } + trades.push(trade); onResponse(global.DEFAULT_OK_RESPONSE, trades); @@ -609,21 +614,15 @@ let sumAssetB = 0; for (let k = 0; k < pTrades.length; k++) { - - sumAssetA = sumAssetA + Number(pTrades[k].amountA); - sumAssetB = sumAssetB + Number(pTrades[k].amountB); - - /* We add the fees */ - - sumAssetA = sumAssetA - Number(pTrades[k].fee); - + let trade = pTrades[k]; + sumAssetA = sumAssetA + Number(trade.amountA); + sumAssetB = sumAssetB + Number(trade.amountB); } + + sumAssetA = Number(sumAssetA.toFixed(8)); + sumAssetB = Number(sumAssetB.toFixed(8)); - sumAssetB = Number(sumAssetB.toFixed(8)); - - if ( - position.amountB !== sumAssetB - ) { + if (position.amountB !== sumAssetB) { logger.write("[ERROR] ordersExecutionCheck -> loopBody -> position.amountB = " + position.amountB); logger.write("[ERROR] ordersExecutionCheck -> loopBody -> sumAssetB = " + sumAssetB); @@ -681,32 +680,10 @@ */ - let sumAssetA = 0; - let sumAssetB = 0; - - for (let k = 0; k < pTrades.length; k++) { - - sumAssetA = sumAssetA + Number(pTrades[k].amountA); - sumAssetB = sumAssetB + Number(pTrades[k].amountB); - - /* We add the fees */ - - sumAssetA = sumAssetA - Number(pTrades[k].fee); - - } - - /* To this we add the current position amounts. */ - - sumAssetA = sumAssetA + Number(exchangePosition.amountA.toFixed(8)); - sumAssetB = sumAssetB + Number(exchangePosition.amountB.toFixed(8)); - - sumAssetA = Number(sumAssetA.toFixed(8)); - sumAssetB = Number(sumAssetB.toFixed(8)); - - if ( - position.amountA !== sumAssetA || - position.amountB !== sumAssetB - ) { + let sumAssetA = Number(exchangePosition.amountA).toFixed(8); + let sumAssetB = Number(exchangePosition.amountB).toFixed(8); + + if (position.amountA !== sumAssetA || position.amountB !== sumAssetB ) { logger.write("[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> position.amountA = " + position.amountA); logger.write("[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> sumAssetA = " + sumAssetA); logger.write("[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> position.amountB = " + position.amountB); @@ -764,57 +741,80 @@ context.newHistoryRecord.newTrades++; /* Calculate Balances */ - + let assetA = 0; + let assetB = 0; + if (trade.type === 'buy') { + let fee = Number(trade.fee) * trade.amountB; + let fixedFee = Number(fee.toFixed(8)); + + assetA = context.executionContext.balance.assetA - Number(trade.amountA); + assetB = context.executionContext.balance.assetB + Number(trade.amountB) - fixedFee; - context.executionContext.balance.assetA = context.executionContext.balance.assetA - Number(trade.amountA); - context.executionContext.balance.assetB = context.executionContext.balance.assetB + Number(trade.amountB); - - context.executionContext.availableBalance.assetB = context.executionContext.availableBalance.assetB + Number(trade.amountB); + let available = context.executionContext.availableBalance.assetB + Number(trade.amountB) - fixedFee; + context.executionContext.availableBalance.assetB = Number(available.toFixed(8)); } if (trade.type === 'sell') { - - context.executionContext.balance.assetA = context.executionContext.balance.assetA + Number(trade.amountA); - context.executionContext.balance.assetB = context.executionContext.balance.assetB - Number(trade.amountB); - - context.executionContext.availableBalance.assetA = context.executionContext.availableBalance.assetA + Number(trade.amountA); + let fee = Number(trade.fee) * trade.amountA; + let fixedFee = Number(fee.toFixed(8)); + + assetA = context.executionContext.balance.assetA + Number(trade.amountA) - fixedFee; + assetB = context.executionContext.balance.assetB - Number(trade.amountB); + + let available = context.executionContext.availableBalance.assetA + Number(trade.amountA) - fixedFee; + context.executionContext.availableBalance.assetA = Number(available.toFixed(8)); } + + context.executionContext.balance.assetA = Number(assetA.toFixed(8)); + context.executionContext.balance.assetB = Number(assetB.toFixed(8)); } /* Calculate Profits */ - if (context.executionContext.investment.assetA > 0) { - + if (context.executionContext.investment.assetA > 0 && context.executionContext.balance.assetA > 0) { context.executionContext.profits.assetA = (context.executionContext.balance.assetA - context.executionContext.investment.assetA) / context.executionContext.investment.assetA; - } - - if (context.executionContext.investment.assetB > 0) { - + }else{ + context.executionContext.profits.assetA = 0; + } + + if (context.executionContext.investment.assetB > 0 && context.executionContext.balance.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; + }else{ + context.executionContext.profits.assetB = 0; + } + + 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; + if (context.executionContext.investment.assetA > 0) { + let convertedAssetsB = 0; + + if(context.executionContext.balance.assetB > 0) + convertedAssetsB = (context.executionContext.balance.assetB - context.executionContext.investment.assetB) * marketRate; + + context.executionContext.combinedProfits.assetA = (context.executionContext.balance.assetA - context.executionContext.investment.assetA + convertedAssetsB ) / context.executionContext.investment.assetA; + + }else{ + context.executionContext.combinedProfits.assetA = 0; + } + + if (context.executionContext.investment.assetB > 0) { + let convertedAssetsA = 0; + + if(context.executionContext.balance.assetA > 0) + convertedAssetsA = (context.executionContext.balance.assetA - context.executionContext.investment.assetA) / marketRate; + + context.executionContext.combinedProfits.assetB = (context.executionContext.balance.assetB - context.executionContext.investment.assetB + convertedAssetsA ) / context.executionContext.investment.assetB; + + }else{ + context.executionContext.combinedProfits.assetB = 0; + } + + 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); diff --git a/Context.js b/Context.js index 9a1598e9d..9e1bd430d 100644 --- a/Context.js +++ b/Context.js @@ -443,20 +443,21 @@ once we advance into multiple competitions scheme. */ - const INITIAL_INVESTMENT = 0.001; // This is just for this release of the platform. + const INITIAL_INVESTMENT_A = 57.23872937; // This is just for this release of the platform. + const INITIAL_INVESTMENT_B = 0; // This is just for this release of the platform. thisObject.executionContext = { investment: { // This is used to calculate profits. - assetA: 0, - assetB: INITIAL_INVESTMENT + assetA: INITIAL_INVESTMENT_A, + assetB: INITIAL_INVESTMENT_B }, balance: { // This is the total balance that includes positions at the order book + funds available to be traded. - assetA: 0, - assetB: INITIAL_INVESTMENT // It starts with the initial investment. + assetA: INITIAL_INVESTMENT_A, + assetB: INITIAL_INVESTMENT_B // 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: INITIAL_INVESTMENT // It starts with the initial investment. + assetA: INITIAL_INVESTMENT_A, + assetB: INITIAL_INVESTMENT_B // It starts with the initial investment. }, profits: { assetA: 0, diff --git a/Poloniex API Client.js b/Poloniex API Client.js index f0891d6d9..f5e6cc60d 100644 --- a/Poloniex API Client.js +++ b/Poloniex API Client.js @@ -411,7 +411,8 @@ stringExchangeErr.indexOf("ENOTFOUND") > 0 || stringExchangeErr.indexOf("ECONNREFUSED") > 0 || stringExchangeErr.indexOf("ESOCKETTIMEDOUT") > 0 || - stringExchangeErr.indexOf("ECONNRESET") > 0) { + stringExchangeErr.indexOf("ECONNRESET") > 0 || + stringExchangeResponse.indexOf("Internal error. Please try again") > 0) { logger.write("[WARN] analizeResponse -> Timeout reached or connection problem while trying to access the Exchange API. Requesting new execution later."); notOkCallBack(global.DEFAULT_RETRY_RESPONSE); From 8a52fec129158d44475ac04e3f9ae307d49366f6 Mon Sep 17 00:00:00 2001 From: matbenitez <34651529+matbenitez@users.noreply.github.com> Date: Sun, 6 May 2018 14:01:52 -0300 Subject: [PATCH 2/3] Orders partially confirmed fixed. --- Assistant.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Assistant.js b/Assistant.js index aa24858ee..3b3119108 100644 --- a/Assistant.js +++ b/Assistant.js @@ -680,9 +680,23 @@ */ - let sumAssetA = Number(exchangePosition.amountA).toFixed(8); - let sumAssetB = Number(exchangePosition.amountB).toFixed(8); + let sumAssetA = 0; + let sumAssetB = 0; + for (let k = 0; k < pTrades.length; k++) { + let trade = pTrades[k]; + sumAssetA = sumAssetA + Number(trade.amountA); + sumAssetB = sumAssetB + Number(trade.amountB); + } + + /* To this we add the current position amounts. */ + + sumAssetA = sumAssetA + Number(exchangePosition.amountA); + sumAssetB = sumAssetB + Number(exchangePosition.amountB); + + sumAssetA = Number(sumAssetA.toFixed(8)); + sumAssetB = Number(sumAssetB.toFixed(8)); + if (position.amountA !== sumAssetA || position.amountB !== sumAssetB ) { logger.write("[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> position.amountA = " + position.amountA); logger.write("[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> sumAssetA = " + sumAssetA); From f22fd26fb180500016c8910ec36fbd0f9b1b3aae Mon Sep 17 00:00:00 2001 From: matbenitez <34651529+matbenitez@users.noreply.github.com> Date: Mon, 7 May 2018 12:10:27 -0300 Subject: [PATCH 3/3] Partial orders Assistant: Fixing issue on patial orders. Context: reseting default amounts Poloniex API Client: Fixing issue when there is an issue with the connection. --- Assistant.js | 4 +++- Context.js | 4 ++-- Poloniex API Client.js | 12 ++++++------ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Assistant.js b/Assistant.js index 3b3119108..d1c0d63a9 100644 --- a/Assistant.js +++ b/Assistant.js @@ -704,7 +704,9 @@ logger.write("[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> sumAssetB = " + sumAssetB); logger.write("[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> Cannot be confirmed that a partially execution was done well."); - callBack(global.DEFAULT_FAIL_RESPONSE); + + /* There are diferences on the responses between the getPosition and getTrades that causes some issues, let's retry. */ + callBack(global.DEFAULT_RETRY_RESPONSE); return; } diff --git a/Context.js b/Context.js index 9e1bd430d..91e0a14ff 100644 --- a/Context.js +++ b/Context.js @@ -443,8 +443,8 @@ once we advance into multiple competitions scheme. */ - const INITIAL_INVESTMENT_A = 57.23872937; // This is just for this release of the platform. - const INITIAL_INVESTMENT_B = 0; // This is just for this release of the platform. + const INITIAL_INVESTMENT_A = 0; // This is just for this release of the platform. + const INITIAL_INVESTMENT_B = .001; // This is just for this release of the platform. thisObject.executionContext = { investment: { // This is used to calculate profits. diff --git a/Poloniex API Client.js b/Poloniex API Client.js index f5e6cc60d..f8bfd88b9 100644 --- a/Poloniex API Client.js +++ b/Poloniex API Client.js @@ -403,16 +403,16 @@ logger.write("[INFO] analizeResponse -> exchangeErr = " + stringExchangeErr); logger.write("[INFO] analizeResponse -> exchangeResponse = " + stringExchangeResponse); - if ( - stringExchangeResponse.indexOf("Connection timed out") > 0 || - stringExchangeResponse.indexOf("Connection Error") > 0 || - stringExchangeResponse.indexOf("Bad gateway") > 0 || - stringExchangeErr.indexOf("ETIMEDOUT") > 0 || + if (stringExchangeErr.indexOf("ETIMEDOUT") > 0 || stringExchangeErr.indexOf("ENOTFOUND") > 0 || stringExchangeErr.indexOf("ECONNREFUSED") > 0 || stringExchangeErr.indexOf("ESOCKETTIMEDOUT") > 0 || stringExchangeErr.indexOf("ECONNRESET") > 0 || - stringExchangeResponse.indexOf("Internal error. Please try again") > 0) { + (stringExchangeResponse !== undefined && ( + stringExchangeResponse.indexOf("Connection timed out") > 0 || + stringExchangeResponse.indexOf("Connection Error") > 0 || + stringExchangeResponse.indexOf("Bad gateway") > 0 || + stringExchangeResponse.indexOf("Internal error. Please try again") > 0))) { logger.write("[WARN] analizeResponse -> Timeout reached or connection problem while trying to access the Exchange API. Requesting new execution later."); notOkCallBack(global.DEFAULT_RETRY_RESPONSE);