From 012aebf5870bc4b7f040c9320e3a852cd2cbc1b2 Mon Sep 17 00:00:00 2001 From: Luis Fernando Molina Date: Tue, 6 Mar 2018 15:01:43 +0100 Subject: [PATCH] Assistant Error handling --- .vs/AACloudPlatform/v15/.suo | Bin 69632 -> 69632 bytes Assistant.js | 505 ++++++++++++++++++++++++++++++++++- 2 files changed, 503 insertions(+), 2 deletions(-) diff --git a/.vs/AACloudPlatform/v15/.suo b/.vs/AACloudPlatform/v15/.suo index afb7d2c91ebdf5e31502d998151ad0e6b38bdd75..f79bcdb1fbcaa0ebcb2cd59e1f9028e1c6201b9d 100644 GIT binary patch delta 362 zcmZozz|ydQWkU`V>w&+jib0zTnLaZzW=~FKv1iPhyp*MyF>|saYdLEM0|P_hvh6cvP6BjT| zW?U{a`NB%R$@1^5Cci%=v$uoP2V1`Q!sj z1s9zFnzA8(bN;)DtdlR6s!iUo-(|W1FQdxj19w>_v)qW-{OW=j<7CAR&Vn9{Kxcx1 z#DRDq+iY{lmopag1SUINRM~vsr32IUGCsyGMga46jKlx{ delta 560 zcmYLEUuaTs6u#&FvALN{+subsn=xupj6K|p`_f!p@S!~{3HDU%Va3XU8bMSZPWb(F^KJ)S&tU=Ylb zR~K)v>m3o5c9=u{Od)^!((n&6uUXm8^M-*o&H87%g-an54nWSDk onResponse -> Retry Later. Requesting Interval Retry."); + callBackFunction(true, nextIntervalLapse); + return; + } + break; + case 'Operation Failed.': { // This is an unexpected exception that we do not know how to handle. + logger.write("[ERROR] getPositionsAtExchange -> onResponse -> Operation Failed. Aborting the process."); + return; + } + break; + } + } } catch (err) { - logger.write("[ERROR] getCandles -> err = " + err); + logger.write("[ERROR] getPositionsAtExchange -> err = " + err); callBack("Operation Failed."); } } + function ordersExecutionCheck(callBack) { + + try { + /* + + Here we check that all the positions we know we have are still at the exchange. If they are not, we will try to take appropiate + actions. Reasons why the positions might not be there are: + + 1. The user / account owner closed the positions manually. + 2. The exchange for some eventuality closed the positions. In some exchanges positions have an expiratin time. + 3. The orders were executed. + + For as 1 and 2 are similar unexpected situations and we will stop the bot execution when we detect we are there. Number 3 is an + expected behaviour and we take appropiate action. + + Also, the position might still be there but it might have been partially executed. To detect that we need to compare the + position amounts we have on file to the one we are receiving from the exchange. + + Before we begin, we have to remove all the orders that have been already closed at the last execution of the bot. + + */ + + let openPositions = []; + + for (let a = 0; a < botContext.executionContext.positions.length; a++) { + + if (botContext.executionContext.positions[a].status === "open") { + + openPositions.push(botContext.executionContext.positions[a]); + + } + } + + botContext.executionContext.positions = openPositions; + + /* Now we can start checking what happened at the exchange. */ + + let i = 0; + + controlLoop(); + + function loopBody() { + + try { + for (let j = 0; j < exchangePositions.length; j++) { + + if (botContext.executionContext.positions[i].id === exchangePositions[j].id) { + + /* + + We need to know if the order was partially executed. To know that, we compare the amounts on file with the ones + received from the exchange. If they are the same, then the order is intact. Otherwise, to confirm a partial execution, + we will request the associated trades from the exchange. + + */ + + if (botContext.executionContext.positions[i].amountB === parseFloat(exchangePositions[j].amountB)) { + + /* Position is still there, untouched. Nothing to do here. */ + + next(); + return; + + } else { + + getPositionTradesAtExchange(botContext.executionContext.positions[i].id, confirmOrderWasPartiallyExecuted); + return; + + function confirmOrderWasPartiallyExecuted(trades) { + + try { + /* + + To confirm everything is ok, we will add all the amounts on trades plus the remaining amounts + at the order at the exchange 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 (k = 0; k < trades.length; k++) { + + sumAssetA = sumAssetA + trades[k].amountA; + sumAssetB = sumAssetB + trades[k].amountB; + + } + + /* To this we add the current position amounts. */ + + sumAssetA = sumAssetA + exchangePositions[j].amountA; + sumAssetB = sumAssetB + exchangePositions[j].amountB; + + /* And finally we add the fees */ + + sumAssetA = sumAssetA + exchangePositions[j].fee; + + if ( + botContext.executionContext.positions[i].amountA !== sumAssetA || + botContext.executionContext.positions[i].amountB !== sumAssetB + ) { + logger.write("[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> Cannot be confirmed that a partially execution was done well."); + callBack("Operation Failed."); + return; + } + + /* + + Confirmed that order was partially executed. Next thing to do is to remember the trades and the new position. + + */ + + botContext.executionContext.positions[i].amountA = exchangePositions[j].amountA; + botContext.executionContext.positions[i].amountB = exchangePositions[j].amountB; + botContext.executionContext.positions[i].date = (new Date(exchangePositions[j].date)).valueOf(); + + for (k = 0; k < trades.length; k++) { + + botContext.executionContext.positions[i].trades.push(trades[k]); + + botContext.newHistoryRecord.newTrades++; + + } + + let newTransaction = { + type: botContext.executionContext.positions[i].type + " partially executed", + position: botContext.executionContext.positions[i] + }; + + botContext.executionContext.transactions.push(newTransaction); + + /* All done. */ + + next(); + + } catch (err) { + logger.write("[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> err = " + err); + callBack("Operation Failed."); + return; + } + } + } + } + } + + /* Position not found: we need to know if the order was executed. */ + + getPositionTradesAtExchange(botContext.executionContext.positions[i].id, confirmOrderWasExecuted); + + function confirmOrderWasExecuted(trades) { + + try { + /* + + 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 (k = 0; k < trades.length; k++) { + + sumAssetA = sumAssetA + trades[k].amountA; + sumAssetB = sumAssetB + trades[k].amountB; + + } + + /* We add the fees */ + + sumAssetA = sumAssetA + exchangePositions[j].fee; + + if ( + botContext.executionContext.positions[i].amountA !== sumAssetA || + botContext.executionContext.positions[i].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."); + callBack("Operation Failed."); + return; + } + + /* + + Confirmed that order was executed. Next thing to do is to remember the trades and change its status. + + */ + + botContext.executionContext.positions[i].status = "executed"; + + for (k = 0; k < trades.length; k++) { + + botContext.executionContext.positions[i].trades.push(trades[k]); + + botContext.newHistoryRecord.newTrades++; + + } + + let newTransaction = { + type: botContext.executionContext.positions[i].type + " executed", + position: botContext.executionContext.positions[i] + }; + + botContext.executionContext.transactions.push(newTransaction); + + /* All done. */ + + next(); + + } catch (err) { + logger.write("[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasExecuted -> err = " + err); + callBack("Operation Failed."); + return; + } + } + + } catch (err) { + logger.write("[ERROR] ordersExecutionCheck -> loopBody -> err = " + err); + callBack("Operation Failed."); + return; + } + } + + function next() { + + i++; + controlLoop(); + + } + + function controlLoop() { + + if (i < botContext.executionContext.positions.length) { + + loopBody(); + + } else { + + final(); + + } + } + + function final() { + + getCandles(); + + } + } catch (err) { + logger.write("[ERROR] ordersExecutionCheck -> err = " + err); + callBack("Operation Failed."); + } + } + + function getPositionTradesAtExchange(pPositionId, callBack) { + + try { + /* + + Given one position, we request all the associated trades to it. + + */ + + exchangeAPI.getExecutedTrades(pPositionId, onResponse); + + function onResponse(err, pTrades) { + + try { + switch (err) { + case null: { // Everything went well, we have the information requested. + callBack(pTrades); + } + break; + case 'Retry Later.': { // Something bad happened, but if we retry in a while it might go through the next time. + logger.write("[ERROR] getPositionTradesAtExchange -> onResponse -> Retry Later. Requesting Interval Retry."); + callBackFunction(true, nextIntervalLapse); + return; + } + break; + case 'Operation Failed.': { // This is an unexpected exception that we do not know how to handle. + logger.write("[ERROR] getPositionTradesAtExchange -> onResponse -> Operation Failed. Aborting the process."); + return; + } + break; + } + } catch (err) { + logger.write("[ERROR] getPositionTradesAtExchange -> onResponse -> err = " + err); + callBack("Operation Failed."); + } + } + } catch (err) { + logger.write("[ERROR] getPositionTradesAtExchange -> err = " + err); + callBack("Operation Failed."); + } + } + + function putPositionAtExchange(pType, pRate, pAmountA, pAmountB, callBack) { + + try { + exchangeAPI.putPosition(market, pType, pRate, pAmountA, pAmountB, onResponse); + + function onResponse(err, pPositionId) { + + try { + switch (err) { + case null: { // Everything went well, we have the information requested. + + let position = { + id: pPositionId, + type: pType, + rate: pRate, + amountA: pAmountA, + amountB: pAmountB, + date: (processDatetime.valueOf()), + status: "open", + trades: [] + }; + + botContext.executionContext.positions.push(position); + + let newTransaction = { + type: "newPosition", + position: position + }; + + botContext.executionContext.transactions.push(newTransaction); + + botContext.newHistoryRecord.newPositions++; + botContext.newHistoryRecord.rate = pRate; + + callBack(); + } + break; + case 'Retry Later.': { // Something bad happened, but if we retry in a while it might go through the next time. + logger.write("[ERROR] putPositionAtExchange -> onResponse -> Retry Later. Requesting Interval Retry."); + callBackFunction(true, nextIntervalLapse); + return; + } + break; + case 'Operation Failed.': { // This is an unexpected exception that we do not know how to handle. + logger.write("[ERROR] putPositionAtExchange -> onResponse -> Operation Failed. Aborting the process."); + return; + } + break; + } + } catch (err) { + logger.write("[ERROR] putPositionAtExchange -> onResponse -> err = " + err); + callBack("Operation Failed."); + } + } + } catch (err) { + logger.write("[ERROR] putPositionAtExchange -> err = " + err); + callBack("Operation Failed."); + } + } + + function movePositionAtExchange(pPosition, pNewRate, callBack) { + + try { + exchangeAPI.movePosition(pPosition, pNewRate, onResponse); + + function onResponse(err, pPositionId) { + + try { + switch (err) { + case null: { // Everything went well, we have the information requested. + + let newPosition = { + id: pPositionId, + type: pPosition.type, + rate: pNewRate, + amountA: pPosition.amountB * pNewRate, + amountB: pPosition.amountB, + date: (processDatetime.valueOf()), + status: "open", + trades: [] + }; + + let oldPosition = JSON.parse(JSON.stringify(pPosition)); + + /* We need to update the position we have on file. */ + + for (let i = 0; i < botContext.executionContext.positions.length; i++) { + + if (botContext.executionContext.positions[i].id === pPosition.id) { + + botContext.executionContext.positions[i] = newPosition; + + break; + } + } + + let newTransaction = { + type: "movePosition", + oldPosition: oldPosition, + newPosition: newPosition + }; + + botContext.executionContext.transactions.push(newTransaction); + + botContext.newHistoryRecord.movedPositions++; + botContext.newHistoryRecord.rate = pNewRate; + + callBack(); + } + break; + case 'Retry Later.': { // Something bad happened, but if we retry in a while it might go through the next time. + logger.write("[ERROR] movePositionAtExchange -> onResponse -> Retry Later. Requesting Interval Retry."); + callBackFunction(true, nextIntervalLapse); + return; + } + break; + case 'Operation Failed.': { // This is an unexpected exception that we do not know how to handle. + logger.write("[ERROR] movePositionAtExchange -> onResponse -> Operation Failed. Aborting the process."); + return; + } + break; + } + } catch (err) { + logger.write("[ERROR] movePositionAtExchange -> onResponse -> err = " + err); + callBack("Operation Failed."); + } + } + } catch (err) { + logger.write("[ERROR] movePositionAtExchange -> err = " + err); + callBack("Operation Failed."); + } + } }; \ No newline at end of file