balance and availableBalance handling
This commit is contained in:
1 parent
4b6fddffff
commit
7b33ee1406
5 files changed
+242
-57
No files matched your search
Binary file not shown.
+204
-49
@@ -14,7 +14,11 @@
|
||||
initialize: initialize,
|
||||
putPosition: putPosition,
|
||||
movePosition: movePosition,
|
||||
getPositions: getPositions
|
||||
getPositions: getPositions,
|
||||
getBalance: getBalance,
|
||||
getAvailableBalance: getAvailableBalance,
|
||||
getInvestment: getInvestment,
|
||||
getProfits: getProfits
|
||||
};
|
||||
|
||||
let bot = BOT;
|
||||
@@ -29,8 +33,6 @@
|
||||
let context;
|
||||
let exchangeAPI;
|
||||
|
||||
const INITIAL_INVESTMENT = 0.001;
|
||||
|
||||
return thisObject;
|
||||
|
||||
function initialize(pContext, pExchangeAPI, callBackFunction) {
|
||||
@@ -178,9 +180,12 @@
|
||||
function loopBody() {
|
||||
|
||||
try {
|
||||
|
||||
let position = context.executionContext.positions[i];
|
||||
|
||||
for (let j = 0; j < exchangePositions.length; j++) {
|
||||
|
||||
if (context.executionContext.positions[i].id === exchangePositions[j].id) {
|
||||
if (position.id === exchangePositions[j].id) {
|
||||
|
||||
/*
|
||||
|
||||
@@ -190,7 +195,7 @@
|
||||
|
||||
*/
|
||||
|
||||
if (context.executionContext.positions[i].amountB === parseFloat(exchangePositions[j].amountB)) {
|
||||
if (position.amountB === parseFloat(exchangePositions[j].amountB)) {
|
||||
|
||||
/* Position is still there, untouched. Nothing to do here. */
|
||||
|
||||
@@ -199,7 +204,7 @@
|
||||
|
||||
} else {
|
||||
|
||||
getPositionTradesAtExchange(context.executionContext.positions[i].id, confirmOrderWasPartiallyExecuted);
|
||||
getPositionTradesAtExchange(position.id, confirmOrderWasPartiallyExecuted);
|
||||
return;
|
||||
|
||||
function confirmOrderWasPartiallyExecuted(pTrades) {
|
||||
@@ -233,8 +238,8 @@
|
||||
sumAssetA = sumAssetA + exchangePositions[j].fee;
|
||||
|
||||
if (
|
||||
context.executionContext.positions[i].amountA !== sumAssetA ||
|
||||
context.executionContext.positions[i].amountB !== sumAssetB
|
||||
position.amountA !== sumAssetA ||
|
||||
position.amountB !== sumAssetB
|
||||
) {
|
||||
logger.write("[ERROR] ordersExecutionCheck -> loopBody -> confirmOrderWasPartiallyExecuted -> Cannot be confirmed that a partially execution was done well.");
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
@@ -247,21 +252,15 @@
|
||||
|
||||
*/
|
||||
|
||||
context.executionContext.positions[i].amountA = exchangePositions[j].amountA;
|
||||
context.executionContext.positions[i].amountB = exchangePositions[j].amountB;
|
||||
context.executionContext.positions[i].date = (new Date(exchangePositions[j].date)).valueOf();
|
||||
position.amountA = exchangePositions[j].amountA;
|
||||
position.amountB = exchangePositions[j].amountB;
|
||||
position.date = (new Date(exchangePositions[j].date)).valueOf();
|
||||
|
||||
for (k = 0; k < pTrades.length; k++) {
|
||||
|
||||
context.executionContext.positions[i].pTrades.push(pTrades[k]);
|
||||
|
||||
context.newHistoryRecord.newTrades++;
|
||||
|
||||
}
|
||||
applyTradesToContext(pTrades);
|
||||
|
||||
let newTransaction = {
|
||||
type: context.executionContext.positions[i].type + " partially executed",
|
||||
position: context.executionContext.positions[i]
|
||||
type: position.type + " partially executed",
|
||||
position: position
|
||||
};
|
||||
|
||||
context.executionContext.transactions.push(newTransaction);
|
||||
@@ -282,7 +281,7 @@
|
||||
|
||||
/* Position not found: we need to know if the order was executed. */
|
||||
|
||||
getPositionTradesAtExchange(context.executionContext.positions[i].id, confirmOrderWasExecuted);
|
||||
getPositionTradesAtExchange(position.id, confirmOrderWasExecuted);
|
||||
|
||||
function getPositionTradesAtExchange(pPositionId, innerCallBack) {
|
||||
|
||||
@@ -362,8 +361,8 @@
|
||||
sumAssetA = sumAssetA + exchangePositions[j].fee;
|
||||
|
||||
if (
|
||||
context.executionContext.positions[i].amountA !== sumAssetA ||
|
||||
context.executionContext.positions[i].amountB !== sumAssetB
|
||||
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.");
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
@@ -376,19 +375,13 @@
|
||||
|
||||
*/
|
||||
|
||||
context.executionContext.positions[i].status = "executed";
|
||||
position.status = "executed";
|
||||
|
||||
for (k = 0; k < pTrades.length; k++) {
|
||||
|
||||
context.executionContext.positions[i].pTrades.push(pTrades[k]);
|
||||
|
||||
context.newHistoryRecord.newTrades++;
|
||||
|
||||
}
|
||||
applyTradesToContext(pTrades);
|
||||
|
||||
let newTransaction = {
|
||||
type: context.executionContext.positions[i].type + " executed",
|
||||
position: context.executionContext.positions[i]
|
||||
type: position.type + " executed",
|
||||
position: position
|
||||
};
|
||||
|
||||
context.executionContext.transactions.push(newTransaction);
|
||||
@@ -436,13 +429,54 @@
|
||||
callBack(global.DEFAULT_OK_RESPONSE);
|
||||
|
||||
}
|
||||
|
||||
function applyTradesToContext(pTrades) {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
logger.write("[ERROR] ordersExecutionCheck -> err = " + err.message);
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function putPosition(pType, pRate, pAmountA, pAmountB, callBack) {
|
||||
function putPosition(pType, pRate, pAmountA, pAmountB, callBackFunction) {
|
||||
|
||||
try {
|
||||
if (FULL_LOG === true) { logger.write("[INFO] putPosition -> Entering function."); }
|
||||
@@ -451,6 +485,62 @@
|
||||
if (FULL_LOG === true) { logger.write("[INFO] putPosition -> pAmountA = " + pAmountA); }
|
||||
if (FULL_LOG === true) { logger.write("[INFO] putPosition -> pAmountB = " + pAmountB); }
|
||||
|
||||
/* Validations that the limits are not surpassed. */
|
||||
|
||||
if (pType === 'buy') {
|
||||
|
||||
if (pAmountA > context.executionContext.availableBalance.assetA) {
|
||||
|
||||
logger.write("[ERROR] putPosition -> Input Validations -> pAmountA is grater than the Available Balance.");
|
||||
logger.write("[ERROR] putPosition -> Input Validations -> pAmountA = " + pAmountA);
|
||||
logger.write("[ERROR] putPosition -> Input Validations -> Available Balance = " + context.executionContext.availableBalance.assetA);
|
||||
|
||||
let err = {
|
||||
result: global.DEFAULT_FAIL_RESPONSE.result;
|
||||
message: 'pAmountA is grater than the Available Balance.'
|
||||
};
|
||||
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (pType === 'sell') {
|
||||
|
||||
if (pAmountB > context.executionContext.availableBalance.assetB) {
|
||||
|
||||
logger.write("[ERROR] putPosition -> Input Validations -> pAmountB is grater than the Available Balance.");
|
||||
logger.write("[ERROR] putPosition -> Input Validations -> pAmountB = " + pAmountB);
|
||||
logger.write("[ERROR] putPosition -> Input Validations -> Available Balance = " + context.executionContext.availableBalance.assetB);
|
||||
|
||||
let err = {
|
||||
result: global.DEFAULT_FAIL_RESPONSE.result;
|
||||
message: 'pAmountB is grater than the Available Balance.'
|
||||
};
|
||||
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (pAmountB * pRate !== pAmountA) {
|
||||
|
||||
logger.write("[ERROR] putPosition -> Input Validations -> pAmountB * pRate !== pAmountA.");
|
||||
logger.write("[ERROR] putPosition -> Input Validations -> pAmountB = " + pAmountA);
|
||||
logger.write("[ERROR] putPosition -> Input Validations -> pAmountB = " + pAmountB);
|
||||
logger.write("[ERROR] putPosition -> Input Validations -> pAmountB = " + pRate);
|
||||
|
||||
let err = {
|
||||
result: global.DEFAULT_FAIL_RESPONSE.result;
|
||||
message: 'pAmountB * pRate !== pAmountA'
|
||||
};
|
||||
|
||||
callBackFunction(err);
|
||||
return;
|
||||
}
|
||||
|
||||
/* All validations passed, we proceed. */
|
||||
|
||||
exchangeAPI.putPosition(global.MARKET, pType, pRate, pAmountA, pAmountB, onResponse);
|
||||
|
||||
function onResponse(err, pPositionId) {
|
||||
@@ -484,37 +574,50 @@
|
||||
context.executionContext.transactions.push(newTransaction);
|
||||
|
||||
context.newHistoryRecord.newPositions++;
|
||||
context.newHistoryRecord.rate = pRate;
|
||||
|
||||
callBack(global.DEFAULT_OK_RESPONSE);
|
||||
recalculateRateAverages();
|
||||
|
||||
/* Recalculate Available Balances */
|
||||
|
||||
if (position.type === 'buy') {
|
||||
|
||||
context.executionContext.availableBalance.assetA = context.executionContext.availableBalance.assetA - trade.amountA;
|
||||
}
|
||||
|
||||
if (position.type === 'sell') {
|
||||
|
||||
context.executionContext.availableBalance.assetB = context.executionContext.availableBalance.assetB - trade.amountB;
|
||||
}
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
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] putPosition -> onResponse -> Retry Later. Requesting Execution Retry.");
|
||||
callBack(global.DEFAULT_RETRY_RESPONSE);
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
|
||||
logger.write("[ERROR] putPosition -> onResponse -> Operation Failed. Aborting the process.");
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write("[ERROR] putPosition -> onResponse -> err = " + err.message);
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write("[ERROR] putPosition -> err = " + err.message);
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function movePosition(pPosition, pNewRate, callBack) {
|
||||
function movePosition(pPosition, pNewRate, callBackFunction) {
|
||||
|
||||
try {
|
||||
if (FULL_LOG === true) { logger.write("[INFO] movePosition -> Entering function."); }
|
||||
@@ -550,9 +653,9 @@
|
||||
|
||||
for (let i = 0; i < context.executionContext.positions.length; i++) {
|
||||
|
||||
if (context.executionContext.positions[i].id === pPosition.id) {
|
||||
if (position.id === pPosition.id) {
|
||||
|
||||
context.executionContext.positions[i] = newPosition;
|
||||
position = newPosition;
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -567,36 +670,88 @@
|
||||
context.executionContext.transactions.push(newTransaction);
|
||||
|
||||
context.newHistoryRecord.movedPositions++;
|
||||
context.newHistoryRecord.rate = pNewRate;
|
||||
|
||||
callBack(global.DEFAULT_OK_RESPONSE);
|
||||
recalculateRateAverages();
|
||||
|
||||
callBackFunction(global.DEFAULT_OK_RESPONSE);
|
||||
}
|
||||
break;
|
||||
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] movePosition -> onResponse -> Retry Later. Requesting Execution Retry.");
|
||||
callBack(global.DEFAULT_RETRY_RESPONSE);
|
||||
callBackFunction(global.DEFAULT_RETRY_RESPONSE);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle.
|
||||
logger.write("[ERROR] movePosition -> onResponse -> Operation Failed. Aborting the process.");
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write("[ERROR] movePosition -> onResponse -> err = " + err.message);
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
logger.write("[ERROR] movePosition -> err = " + err.message);
|
||||
callBack(global.DEFAULT_FAIL_RESPONSE);
|
||||
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
|
||||
}
|
||||
}
|
||||
|
||||
function recalculateRateAverages() {
|
||||
|
||||
/* This function calculates the weighted rates of buy and sell positions. This is a way to summarize with only one rate, where the positions are. */
|
||||
|
||||
let sumBuyWeightedRates = 0;
|
||||
let sumSellWeightedRates = 0;
|
||||
|
||||
let sumBuyWeights = 0;
|
||||
let sumSellWeights = 0;
|
||||
|
||||
for (let i = 0; i < context.executionContext.positions.length; i++) {
|
||||
|
||||
let position = context.executionContext.positions[i];
|
||||
|
||||
if (position.type === 'buy') {
|
||||
|
||||
sumBuyWeightedRates = sumBuyWeightedRates + position.rate * position.amountB
|
||||
sumBuyWeights = sumBuyWeights + position.amountB;
|
||||
|
||||
}
|
||||
|
||||
if (position.type === 'sell') {
|
||||
|
||||
sumSellWeightedRates = sumSellWeightedRates + position.rate * position.amountB
|
||||
sumSellWeights = sumSellWeights + position.amountB;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
context.newHistoryRecord.buyAvgRate = sumBuyWeightedRates / sumBuyWeights;
|
||||
context.newHistoryRecord.sellAvgRate = sumSellWeightedRates / sumSellWeights;
|
||||
}
|
||||
|
||||
|
||||
function getPositions() {
|
||||
return JSON.parse(JSON.stringify(context.executionContext.positions));
|
||||
}
|
||||
|
||||
function getBalance() {
|
||||
return JSON.parse(JSON.stringify(context.executionContext.balance));
|
||||
}
|
||||
|
||||
function getAvailableBalance() {
|
||||
return JSON.parse(JSON.stringify(context.executionContext.availableBalance));
|
||||
}
|
||||
|
||||
function getInvestment() {
|
||||
return JSON.parse(JSON.stringify(context.executionContext.investment));
|
||||
}
|
||||
|
||||
function getProfits() {
|
||||
return JSON.parse(JSON.stringify(context.executionContext.profits));
|
||||
}
|
||||
};
|
||||
+27
-7
@@ -38,10 +38,15 @@
|
||||
executionContext: undefined, // Here is the business information of the last execution of this bot process.
|
||||
newHistoryRecord : {
|
||||
date: undefined,
|
||||
rate: 0, // This will be used to know where to plot this information in the time line.
|
||||
buyAvgRate: 0,
|
||||
sellAvgRate: 0,
|
||||
newPositions: 0,
|
||||
newTrades: 0,
|
||||
movedPositions: 0
|
||||
movedPositions: 0,
|
||||
profitsAssetA: 0,
|
||||
profitsAssetB: 0,
|
||||
profitsCombinedInA: 0,
|
||||
profitsCombinedInB: 0
|
||||
},
|
||||
initialize: initialize,
|
||||
saveThemAll: saveThemAll
|
||||
@@ -316,11 +321,20 @@
|
||||
thisObject.executionHistory = [];
|
||||
|
||||
thisObject.executionContext = {
|
||||
investment: {
|
||||
investment: { // This is used to calculate profits.
|
||||
assetA: 0,
|
||||
assetB: 0
|
||||
assetB: global.INITIAL_INVESTMENT
|
||||
},
|
||||
availableBalance: {
|
||||
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.
|
||||
},
|
||||
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.
|
||||
},
|
||||
profitsAsset: global.PROFIT_BASE_ASSET,
|
||||
profits: {
|
||||
assetA: 0,
|
||||
assetB: 0
|
||||
},
|
||||
@@ -467,10 +481,16 @@
|
||||
|
||||
let newRecord = [
|
||||
thisObject.newHistoryRecord.date.valueOf(),
|
||||
thisObject.newHistoryRecord.rate,
|
||||
thisObject.newHistoryRecord.buyAvgRate,
|
||||
thisObject.newHistoryRecord.sellAvgRate,
|
||||
thisObject.newHistoryRecord.marketRate,
|
||||
thisObject.newHistoryRecord.newPositions,
|
||||
thisObject.newHistoryRecord.newTrades,
|
||||
thisObject.newHistoryRecord.movedPositions
|
||||
thisObject.newHistoryRecord.movedPositions,
|
||||
thisObject.newHistoryRecord.profitsAssetA,
|
||||
thisObject.newHistoryRecord.profitsAssetB,
|
||||
thisObject.newHistoryRecord.profitsCombinedInA,
|
||||
thisObject.newHistoryRecord.profitsCombinedInB
|
||||
];
|
||||
|
||||
thisObject.executionHistory.push(newRecord);
|
||||
|
||||
@@ -127,6 +127,16 @@ 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. */
|
||||
|
||||
|
||||
|
||||
const START_ALL_MONTHS = false;
|
||||
|
||||
+1
-1
@@ -2,5 +2,5 @@
|
||||
"bot": {
|
||||
"path": "../Bots/AAMasters/AAMariam-Trading-Bot"
|
||||
},
|
||||
"stopGracefully": "false"
|
||||
"stopGracefully": "true"
|
||||
}
|
||||
Reference in new issue
Block a user