From c1fe5c714a7eff402dbdc4534d390b1aab4fba8d Mon Sep 17 00:00:00 2001 From: Matias Benitez Date: Wed, 20 Jun 2018 09:24:51 -0300 Subject: [PATCH] Adding baseline version --- Project.njsproj | 1 + Trading-Process/User.Bot.js | 477 +++++++++++++++++++----------------- package-lock.json | 5 + package.json | 3 +- 4 files changed, 264 insertions(+), 222 deletions(-) create mode 100644 package-lock.json diff --git a/Project.njsproj b/Project.njsproj index c3fab12e5..319a734ad 100644 --- a/Project.njsproj +++ b/Project.njsproj @@ -14,6 +14,7 @@ 14.0 $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) Project + Debug|Any CPU diff --git a/Trading-Process/User.Bot.js b/Trading-Process/User.Bot.js index 60ee46e43..281b70369 100644 --- a/Trading-Process/User.Bot.js +++ b/Trading-Process/User.Bot.js @@ -1,12 +1,8 @@ -exports.newUserBot = function newUserBot(BOT, DEBUG_MODULE, COMMONS_MODULE) { - let bot = BOT; +exports.newUserBot = function newUserBot(bot, logger) { - const FULL_LOG = true; const MODULE_NAME = "User Bot"; + const FULL_LOG = true; const LOG_INFO = true; - const logger = DEBUG_MODULE.newDebugLog(); - logger.fileName = MODULE_NAME; - logger.bot = bot; let thisObject = { initialize: initialize, @@ -20,7 +16,7 @@ function initialize(pAssistant, callBackFunction) { try { - if (LOG_INFO === true) { logger.write("[INFO] initialize -> Entering function."); } + if (LOG_INFO === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } logger.fileName = MODULE_NAME; @@ -32,159 +28,92 @@ callBackFunction(global.DEFAULT_OK_RESPONSE); } catch (err) { - logger.write("[ERROR] initialize -> onDone -> err = " + err.message); + logger.write(MODULE_NAME, "[ERROR] initialize -> onDone -> err = " + err.message); callBackFunction(global.DEFAULT_RETRY_RESPONSE); } } function start(callBackFunction) { - try { - if (LOG_INFO === true) { logger.write("[INFO] start -> Entering function."); } + if (LOG_INFO === true) { logger.write(MODULE_NAME, "[INFO] start -> Entering function."); } - let market = global.MARKET; - /* + let market = global.MARKET; - This trading bot will use an strategy based on the interpretation of the Linear Regression Curve Channel. + /* + This trading bot will use an strategy based on the interpretation of the Linear Regression Curve Channel. + */ - */ + businessLogic(onDone); - businessLogic(onDone); - - function onDone(err) { - try { - switch (err.result) { - case global.DEFAULT_OK_RESPONSE.result: { - logger.write("[INFO] start -> onDone -> Execution finished well. :-)"); - callBackFunction(global.DEFAULT_OK_RESPONSE); - return; - } - 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] start -> onDone -> Retry Later. Requesting Execution Retry."); - callBackFunction(global.DEFAULT_RETRY_RESPONSE); - return; - } - case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. - logger.write("[ERROR] start -> onDone -> Operation Failed. Aborting the process. err = " + err.message); - callBackFunction(global.DEFAULT_RETRY_RESPONSE); - return; - } + function onDone(err) { + try { + switch (err.result) { + case global.DEFAULT_OK_RESPONSE.result: { + logger.write(MODULE_NAME, "[INFO] start -> onDone -> Execution finished well. :-)"); + callBackFunction(global.DEFAULT_OK_RESPONSE); + return; + } + 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(MODULE_NAME, "[ERROR] start -> onDone -> Retry Later. Requesting Execution Retry."); + callBackFunction(global.DEFAULT_RETRY_RESPONSE); + return; + } + case global.DEFAULT_FAIL_RESPONSE.result: { // This is an unexpected exception that we do not know how to handle. + logger.write(MODULE_NAME, "[ERROR] start -> onDone -> Operation Failed. Aborting the process. err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + return; } - } catch (err) { - logger.write("[ERROR] start -> onDone -> err = " + err.message); - callBackFunction(global.DEFAULT_RETRY_RESPONSE); } + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> onDone -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); } + } - function businessLogic(callBack) { - if (LOG_INFO === true) { logger.write("[INFO] start -> businessLogic -> Entering function."); } + function businessLogic(callBack) { + if (LOG_INFO === true) { logger.write(MODULE_NAME, "[INFO] start -> businessLogic -> Entering function."); } - getChannelTilt(botDecision); + getChannelTilt(botDecision); - function botDecision(err, channelTilt) { - if (LOG_INFO === true) { logger.write("[INFO] start -> businessLogic -> botDecision -> LRC Channel Tilt:" + channelTilt); } + function botDecision(err, channelTilt) { + if (LOG_INFO === true) { logger.write(MODULE_NAME, "[INFO] start -> businessLogic -> botDecision -> LRC Channel Tilt:" + channelTilt); } - if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - logger.write("[ERROR] start -> businessLogic -> err = " + err.message); - callBack(global.DEFAULT_RETRY_RESPONSE); + if (err.result !== global.DEFAULT_OK_RESPONSE.result) { + logger.write(MODULE_NAME, "[ERROR] start -> businessLogic -> botDecision -> err = " + err.message); + callBack(global.DEFAULT_FAIL_RESPONSE); + } else { + if (channelTilt == 1) { + createBuyPosition(callBack); + } else if (channelTilt == -1) { + createSellPosition(callBack); } else { - if (channelTilt == 1) { - createBuyPosition(callBack); - } else if (channelTilt == -1) { - createSellPosition(callBack); - } else { - if (LOG_INFO === true) { logger.write("[INFO] start -> processBotDecision -> Nothing to do, there isn't a sell or buy oportunity."); } + if (LOG_INFO === true) { logger.write(MODULE_NAME, "[INFO] start -> businessLogic -> botDecision -> Nothing to do, there isn't a sell or buy oportunity."); } - callBack(global.DEFAULT_OK_RESPONSE); - } + callBack(global.DEFAULT_OK_RESPONSE); } } - } + } + } - function createBuyPosition(callBack) { - if (LOG_INFO === true) { logger.write("[INFO] start -> createBuyPosition -> Entering function."); } - - let positions = assistant.getPositions(); - let assetABalance = assistant.getAvailableBalance().assetA; - let currentRate = assistant.getMarketRate(); - let amountA = assistant.getAvailableBalance().assetA; - let amountB = amountA / currentRate; - - if(positions.length > 0 && positions[0].type === "buy" && (bot.processDatetime.valueOf() - positions[0].date) > (60000 * 5)){ - - assistant.movePosition(positions[0], currentRate, callBack); - - if (LOG_INFO === true) { logger.write("[INFO] start -> createBuyPosition -> Artuditu is moving an existing position to a new rate: " + currentRate.toFixed(8) + ". Position: " + JSON.stringify(positions[0])); } - - let message = "I'm moving an existing buy position to a new rate: " + currentRate.toFixed(8); - assistant.sendMessage(1, "Moving Position", message); + function getChannelTilt(callBack) { + if (LOG_INFO === true) { logger.write(MODULE_NAME, "[INFO] start -> businessLogic -> getChannelTilt -> Entering function."); } - - } else if(assetABalance > 0){ - - assistant.putPosition("buy", currentRate, amountA, amountB, callBack); - - let message = "I'm creating a new buy position at rate: " + currentRate.toFixed(8) + ". " + MARKET.assetA +" amount: " + amountA.toFixed(8) + ". " + MARKET.assetB + " amount: " + amountB.toFixed(8); - assistant.sendMessage(1, "Buying", message); - - } else { - if (LOG_INFO === true) { logger.write("[INFO] start -> createBuyPosition -> There is not enough available balance to buy. Available balance: " + assetABalance ); } - - callBack(global.DEFAULT_OK_RESPONSE); - } - } - - function createSellPosition(callBack) { - if (LOG_INFO === true) { logger.write("[INFO] start -> createSellPosition -> Entering function."); } - - let positions = assistant.getPositions(); - let assetBBalance = assistant.getAvailableBalance().assetB; - let currentRate = assistant.getMarketRate(); - let amountB = assistant.getAvailableBalance().assetB; - let amountA = amountB * currentRate; + const CHANNEL_DOWN = -1; + const CHANNEL_UP = 1; + const NO_CHANNEL = 0; + let lrcPoint, previousLRCPoint; - if(positions.length > 0 && positions[0].type === "sell" && (bot.processDatetime.valueOf() - positions[0].date) > (60000 * 5)){ - - assistant.movePosition(positions[0], currentRate, callBack); - - if (LOG_INFO === true) { logger.write("[INFO] start -> createBuyPosition -> Artuditu is moving an existing position to a new rate: " + currentRate.toFixed(8) + ". Position: " + JSON.stringify(positions[0])); } - - let message = "I'm moving an existing sell position to a new rate: " + currentRate.toFixed(8); - assistant.sendMessage(1, "Moving Position", message); + let queryDate = new Date(bot.processDatetime); + getLRCPointsFile(queryDate, onLRCPointsFileReceived); - }else if(assetBBalance > 0){ - - assistant.putPosition("sell", currentRate, amountA, amountB, callBack); - - if (LOG_INFO === true) { logger.write("[INFO] start -> createSellPosition -> Artuditu put a new SELL Position at rate: " + currentRate + ". Amount traded asset A: " + amountA + ". Amount traded asset B: " + amountB); } - - let message = "I'm creating a new sell position at rate: " + currentRate.toFixed(8) + ". " + MARKET.assetA +" amount: " + amountA.toFixed(8) + ". " + MARKET.assetB + " amount: " + amountB.toFixed(8); - assistant.sendMessage(1, "Selling", message); - - } else { - if (LOG_INFO === true) { logger.write("[INFO] start -> createBuyPosition -> There is not enough available balance to sell. Available balance: " + assetBBalance ); } - - callBack(global.DEFAULT_OK_RESPONSE); - } - - } + function onLRCPointsFileReceived(err, lrcPointsFile) { + if (LOG_INFO === true) { logger.write(MODULE_NAME, "[INFO] start -> businessLogic -> getChannelTilt -> onLRCPointsFileReceived."); } - function getChannelTilt(callBack) { - if (LOG_INFO === true) { logger.write("[INFO] start -> getChannelTilt -> Entering function."); } - - const CHANNEL_DOWN = -1; - const CHANNEL_UP = 1; - const NO_CHANNEL = 0; - let lrcPoint, previousLRCPoint; - - let queryDate = new Date(bot.processDatetime); - getLRCPointsFile(queryDate, onLRCPointsFileReceived); - - function onLRCPointsFileReceived(err, lrcPointsFile) { - if (LOG_INFO === true) { logger.write("[INFO] start -> getChannelTilt -> onLRCPointsFileReceived."); } + let lastIndexLrcPointsFile = lrcPointsFile.length - 1; + let lastAvailableDateTime = lrcPointsFile[lastIndexLrcPointsFile][0]; + if (bot.processDatetime.valueOf() <= lastAvailableDateTime || !isExecutionToday()) { for (let i = 0; i < lrcPointsFile.length; i++) { - - if (lrcPointsFile[i][0] === bot.processDatetime.valueOf()) { + if (bot.processDatetime.valueOf() >= lrcPointsFile[i][0] && bot.processDatetime.valueOf() < lrcPointsFile[i][1]) { lrcPoint = { begin: lrcPointsFile[i][0], end: lrcPointsFile[i][1], @@ -192,7 +121,6 @@ mid: lrcPointsFile[i][3], max: lrcPointsFile[i][4] }; - if (i >= 1) { let previous = i - 1; previousLRCPoint = { @@ -209,106 +137,215 @@ queryDate.setDate(queryDate.getDate() - 1); getLRCPointsFile(queryDate, onPreviousLRCPointsFileReceived); } - return; } } - callBack(global.DEFAULT_OK_RESPONSE, NO_CHANNEL); - } + logger.write(MODULE_NAME, "[ERROR] start -> businessLogic -> getChannelTilt -> onLRCPointsFileReceived. The expected LRC Point was not found."); + callBack(global.DEFAULT_FAIL_RESPONSE); + } else { + // Running live we will process last available LRCPoint only if it's delayed 5 minutes top + let maxTolerance = 5 * 60 * 1000; + if (bot.processDatetime.valueOf() <= (lastAvailableDateTime + maxTolerance)) { + lrcPoint = { + begin: lrcPointsFile[lastIndexLrcPointsFile][0], + end: lrcPointsFile[lastIndexLrcPointsFile][1], + min: lrcPointsFile[lastIndexLrcPointsFile][2], + mid: lrcPointsFile[lastIndexLrcPointsFile][3], + max: lrcPointsFile[lastIndexLrcPointsFile][4] + }; - function onPreviousLRCPointsFileReceived(err, lrcPointsFile) { - if (LOG_INFO === true) { logger.write("[INFO] start -> getChannelTilt -> onLRCPointsFileReceived."); } + if (lastIndexLrcPointsFile >= 1) { + let previous = lastIndexLrcPointsFile - 1; + previousLRCPoint = { + begin: lrcPointsFile[previous][0], + end: lrcPointsFile[previous][1], + min: lrcPointsFile[previous][2], + mid: lrcPointsFile[previous][3], + max: lrcPointsFile[previous][4] + }; - let previous = lrcPointsFile.length - 2; - previousLRCPoint = { - begin: lrcPointsFile[previous][0], - end: lrcPointsFile[previous][1], - min: lrcPointsFile[previous][2], - mid: lrcPointsFile[previous][3], - max: lrcPointsFile[previous][4] - }; + applyBotRules(); - applyBotRules(); - } - - function applyBotRules() { - if (LOG_INFO === true) { logger.write("[INFO] start -> getChannelTilt -> applyBotRules -> LRC Point Found: " + JSON.stringify(lrcPoint)); } - - let channelTilt = NO_CHANNEL; - let ruleApplied = ""; - - if (lrcPoint.mid < lrcPoint.mid && lrcPoint.min > lrcPoint.mid && lrcPoint.mid < lrcPoint.min) { - if (lrcPoint.min > previousLrc15 && lrcPoint.mid > previousLrc30 && lrcPoint.mid > previousLrc60) { - channelTilt = CHANNEL_UP; // The channel points UP - ruleApplied += "Rule_1."; - } - } - - if (lrcPoint.min < lrcPoint.mid && lrcPoint.mid > lrcPoint.mid && lrcPoint.mid < lrcPoint.mid) { - if (lrcPoint.min < previousLrc15 && lrcPoint.mid < previousLrc30 && lrcPoint.mid < previousLrc60) { - channelTilt = CHANNEL_DOWN; // The channel points DOWN - ruleApplied += "Rule_2."; - } - } - - if (lrcPoint.min < previousLrc15 && lrcPoint.mid <= previousLrc30) { - // 15 AND 30 changed direction from up to down - channelTilt = CHANNEL_DOWN; - ruleApplied += "Rule_3a."; - } - - if (lrcPoint.min > previousLrc15 && lrcPoint.mid >= previousLrc30) { - // 15 AND 30 changed direction from down to up - channelTilt = CHANNEL_UP; - ruleApplied += "Rule_3b."; - } - - let logMessage = bot.processDatetime.toISOString() + "\t" + ruleApplied + "\t" + channelTilt + "\t" + lrcPoint.min + "\t" + lrcPoint.mid + "\t" + lrcPoint.mid; - if (LOG_INFO === true) { logger.write("[INFO] start -> getChannelTilt -> applyBotRules -> Results: " + logMessage); } - - callBack(global.DEFAULT_OK_RESPONSE, channelTilt); - - } - } - - function getLRCPointsFile(dateTime, callback) { - try { - if (FULL_LOG === true) { logger.write("[INFO] start -> getChannelTilt -> getLRCPointsFile -> Entering function."); } - - let periodName = "30-min"; - let datePath = dateTime.getUTCFullYear() + "/" + pad(dateTime.getUTCMonth() + 1, 2) + "/" + pad(dateTime.getUTCDate(), 2); - let filePath = "LRC-Points/Multi-Period-Daily/" + periodName + "/" + datePath; - let fileName = market.assetA + '_' + market.assetB + ".json" - - gaussStorage.getTextFile(filePath, fileName, onFileReceived); - - function onFileReceived(err, text) { - if (err.result === global.DEFAULT_OK_RESPONSE.result) { - if (FULL_LOG === true) { logger.write("[INFO] start -> getChannelTilt -> getLRCPointsFile -> onFileReceived > Entering Function."); } - - let lrcPointsFile = JSON.parse(text); - callback(global.DEFAULT_OK_RESPONSE, lrcPointsFile); } else { - logger.write("[ERROR] start -> getChannelTilt -> getLRCPointsFile -> onFileReceived -> Failed to get the file. Will abort the process and request a retry."); - callBackFunction(global.DEFAULT_RETRY_RESPONSE); - return; + queryDate.setDate(queryDate.getDate() - 1); + getLRCPointsFile(queryDate, onPreviousLRCPointsFileReceived); } - } - } catch (err) { - logger.write("[ERROR] start -> getChannelTilt -> getLRCPointsFile -> err = " + err.message); - callBackFunction(global.DEFAULT_RETRY_RESPONSE); + } else { + if (LOG_INFO === true) logger.write(MODULE_NAME, "[WARN] start -> getChannelTilt -> onLRCPointsFileReceived. Available candle older than 5 minutes. Skeeping execution."); + + callBack(global.DEFAULT_OK_RESPONSE, NO_CHANNEL); // TODO CUSTOM_OK_RESPONSE + } } } - function pad(str, max) { - str = str.toString(); - return str.length < max ? pad("0" + str, max) : str; + function isExecutionToday() { + let localDate = new Date(); + let today = new Date(Date.UTC( + localDate.getUTCFullYear(), + localDate.getUTCMonth(), + localDate.getUTCDate())); + + return (today.getUTCFullYear() === bot.processDatetime.getUTCFullYear() + && today.getUTCMonth() === bot.processDatetime.getUTCMonth() + && today.getUTCDate() === bot.processDatetime.getUTCDate()); } - } catch (err) { - logger.write("[ERROR] start -> err = " + err.message); - callBackFunction(global.DEFAULT_RETRY_RESPONSE); + function onPreviousLRCPointsFileReceived(err, lrcPointsFile) { + if (LOG_INFO === true) { logger.write(MODULE_NAME, "[INFO] start -> getChannelTilt -> onLRCPointsFileReceived."); } + + let previous = lrcPointsFile.length - 1; + previousLRCPoint = { + begin: lrcPointsFile[previous][0], + end: lrcPointsFile[previous][1], + min: lrcPointsFile[previous][2], + mid: lrcPointsFile[previous][3], + max: lrcPointsFile[previous][4] + }; + + applyBotRules(); + } + + function applyBotRules() { + if (LOG_INFO === true) { logger.write(MODULE_NAME, "[INFO] start -> getChannelTilt -> applyBotRules -> LRC Point Found: " + JSON.stringify(lrcPoint)); } + + let channelTilt = NO_CHANNEL; + let ruleApplied = ""; + + if (lrcPoint.mid < lrcPoint.mid && lrcPoint.min > lrcPoint.mid && lrcPoint.mid < lrcPoint.min) { + if (lrcPoint.min > previousLRCPoint.min && lrcPoint.mid > previousLRCPoint.mid && lrcPoint.mid > previousLRCPoint.max) { + channelTilt = CHANNEL_UP; // The channel points UP + ruleApplied += "Rule_1."; + } + } + + if (lrcPoint.min < lrcPoint.mid && lrcPoint.mid > lrcPoint.mid && lrcPoint.mid < lrcPoint.mid) { + if (lrcPoint.min < previousLRCPoint.min && lrcPoint.mid < previousLRCPoint.mid && lrcPoint.mid < previousLRCPoint.max) { + channelTilt = CHANNEL_DOWN; // The channel points DOWN + ruleApplied += "Rule_2."; + } + } + + if (lrcPoint.min < previousLRCPoint.min && lrcPoint.mid <= previousLRCPoint.mid) { + // 15 AND 30 changed direction from up to down + channelTilt = CHANNEL_DOWN; + ruleApplied += "Rule_3a."; + } + + if (lrcPoint.min > previousLRCPoint.min && lrcPoint.mid >= previousLRCPoint.mid) { + // 15 AND 30 changed direction from down to up + channelTilt = CHANNEL_UP; + ruleApplied += "Rule_3b."; + } + + let logMessage = bot.processDatetime.toISOString() + "\t" + ruleApplied + "\t" + channelTilt + "\t" + lrcPoint.min + "\t" + lrcPoint.mid + "\t" + lrcPoint.mid; + if (LOG_INFO === true) { logger.write(MODULE_NAME, "[INFO] start -> getChannelTilt -> applyBotRules -> Results: " + logMessage); } + + callBack(global.DEFAULT_OK_RESPONSE, channelTilt); + } } + + function getLRCPointsFile(dateTime, callback) { + try { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> businessLogic -> getLRCPointsFile -> Entering function."); } + + let periodName = "30-min"; + let datePath = dateTime.getUTCFullYear() + "/" + pad(dateTime.getUTCMonth() + 1, 2) + "/" + pad(dateTime.getUTCDate(), 2); + let filePath = "LRC-Points/Multi-Period-Daily/" + periodName + "/" + datePath; + let fileName = market.assetA + '_' + market.assetB + ".json" + + gaussStorage.getTextFile(filePath, fileName, onFileReceived); + + function onFileReceived(err, text) { + if (err.result === global.DEFAULT_OK_RESPONSE.result) { + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] start -> getChannelTilt -> getLRCPointsFile -> onFileReceived > Entering Function."); } + + let lrcPointsFile = JSON.parse(text); + callback(global.DEFAULT_OK_RESPONSE, lrcPointsFile); + } else { + logger.write(MODULE_NAME, "[ERROR] start -> getChannelTilt -> getLRCPointsFile -> onFileReceived -> Failed to get the file. Will abort the process and request a retry."); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + return; + } + } + + } catch (err) { + logger.write(MODULE_NAME, "[ERROR] start -> getChannelTilt -> getLRCPointsFile -> err = " + err.message); + callBackFunction(global.DEFAULT_FAIL_RESPONSE); + } + } + + function createBuyPosition(callBack) { + if (LOG_INFO === true) { logger.write(MODULE_NAME, "[INFO] start -> businessLogic -> createBuyPosition -> Entering function."); } + + let positions = assistant.getPositions(); + let assetABalance = assistant.getAvailableBalance().assetA; + let currentRate = assistant.getMarketRate(); + let amountA = assistant.getAvailableBalance().assetA; + let amountB = amountA / currentRate; + + if(positions.length > 0 && positions[0].type === "buy" && (bot.processDatetime.valueOf() - positions[0].date) > (60000 * 5)){ + + assistant.movePosition(positions[0], currentRate, callBack); + + if (LOG_INFO === true) { logger.write(MODULE_NAME, "[INFO] start -> businessLogic -> createBuyPosition -> Artuditu is moving an existing position to a new rate: " + currentRate.toFixed(8) + ". Position: " + JSON.stringify(positions[0])); } + + let message = "I'm moving an existing buy position to a new rate: " + currentRate.toFixed(8); + assistant.sendMessage(1, "Moving Position", message); + + + } else if(assetABalance > 0){ + + assistant.putPosition("buy", currentRate, amountA, amountB, callBack); + + let message = "I'm creating a new buy position at rate: " + currentRate.toFixed(8) + ". " + MARKET.assetA +" amount: " + amountA.toFixed(8) + ". " + MARKET.assetB + " amount: " + amountB.toFixed(8); + assistant.sendMessage(1, "Buying", message); + + } else { + if (LOG_INFO === true) { logger.write(MODULE_NAME, "[INFO] start -> businessLogic -> createBuyPosition -> There is not enough available balance to buy. Available balance: " + assetABalance ); } + + callBack(global.DEFAULT_OK_RESPONSE); + } + } + + function createSellPosition(callBack) { + if (LOG_INFO === true) { logger.write(MODULE_NAME, "[INFO] start -> businessLogic -> createSellPosition -> Entering function."); } + + let positions = assistant.getPositions(); + let assetBBalance = assistant.getAvailableBalance().assetB; + let currentRate = assistant.getMarketRate(); + let amountB = assistant.getAvailableBalance().assetB; + let amountA = amountB * currentRate; + + if(positions.length > 0 && positions[0].type === "sell" && (bot.processDatetime.valueOf() - positions[0].date) > (60000 * 5)){ + + assistant.movePosition(positions[0], currentRate, callBack); + + if (LOG_INFO === true) { logger.write(MODULE_NAME, "[INFO] start -> businessLogic -> createBuyPosition -> Artuditu is moving an existing position to a new rate: " + currentRate.toFixed(8) + ". Position: " + JSON.stringify(positions[0])); } + + let message = "I'm moving an existing sell position to a new rate: " + currentRate.toFixed(8); + assistant.sendMessage(1, "Moving Position", message); + + }else if(assetBBalance > 0){ + + assistant.putPosition("sell", currentRate, amountA, amountB, callBack); + + if (LOG_INFO === true) { logger.write(MODULE_NAME, "[INFO] start -> businessLogic -> createSellPosition -> Artuditu put a new SELL Position at rate: " + currentRate + ". Amount traded asset A: " + amountA + ". Amount traded asset B: " + amountB); } + + let message = "I'm creating a new sell position at rate: " + currentRate.toFixed(8) + ". " + MARKET.assetA +" amount: " + amountA.toFixed(8) + ". " + MARKET.assetB + " amount: " + amountB.toFixed(8); + assistant.sendMessage(1, "Selling", message); + + } else { + if (LOG_INFO === true) { logger.write(MODULE_NAME, "[INFO] start -> businessLogic -> createBuyPosition -> There is not enough available balance to sell. Available balance: " + assetBBalance ); } + + callBack(global.DEFAULT_OK_RESPONSE); + } + } + + function pad(str, max) { + str = str.toString(); + return str.length < max ? pad("0" + str, max) : str; + } + } }; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..4c1670f94 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "AAArtudito", + "version": "1.0.0", + "lockfileVersion": 1 +} diff --git a/package.json b/package.json index bf08fd3ef..a3a80b8a2 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,5 @@ }, "author": "Matias-Benitez", "license": "ISC", - "dependencies": { - } + "dependencies": {} }