From 92a9479ce9f9660defa4e743404d4ab548112023 Mon Sep 17 00:00:00 2001 From: Matias Date: Sun, 31 Mar 2019 23:04:10 +0200 Subject: [PATCH] Adding basic coss exchange integration --- Exchange/ExchangeAPI.js | 14 +- Exchange/wrappers/coss.js | 340 ++++++++++++++++++++++++++ Exchange/wrappers/cossClient.js | 178 ++++++++++++++ Exchange/wrappers/cossProperties.json | 23 ++ ExtractionBotProcessMainLoop.js | 18 +- TradingBotProcessMainLoop.js | 6 +- 6 files changed, 563 insertions(+), 16 deletions(-) create mode 100644 Exchange/wrappers/coss.js create mode 100644 Exchange/wrappers/cossClient.js create mode 100644 Exchange/wrappers/cossProperties.json diff --git a/Exchange/ExchangeAPI.js b/Exchange/ExchangeAPI.js index 1f29542b4..d95e8c2a1 100644 --- a/Exchange/ExchangeAPI.js +++ b/Exchange/ExchangeAPI.js @@ -1,4 +1,4 @@ -exports.newExchangeAPI = function newExchangeAPI(logger, authToken) { +exports.newExchangeAPI = function newExchangeAPI(logger, exchangeName) { /* @@ -31,7 +31,13 @@ if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] initialize -> Entering function."); } - let botExchange = 'Poloniex'; + let botExchange + if (exchangeName === undefined) { + botExchange = 'Poloniex'; // Default Value + } else { + botExchange = exchangeName; + } + let exchange = botExchange.toLowerCase() + 'Client.js'; let api = require('./wrappers/' + exchange); @@ -45,7 +51,7 @@ let auth = require('../utils/auth') let authTokenCloud = await auth.authenticate() accessToken = 'Bearer ' + authTokenCloud - } + } let keyVaultAPI = createKeyVaultAPIClient(accessToken, keyId, cloneId) apiClient = api.newAPIClient(keyVaultAPI, logger); @@ -60,7 +66,7 @@ function createKeyVaultAPIClient(accessToken, keyId, cloneId) { if (global.LOG_CONTROL[MODULE_NAME].logInfo === true) { logger.write(MODULE_NAME, "[INFO] createKeyVaultAPIClient -> Entering function."); } - + const keyVaultAPI = {} keyVaultAPI.signTransaction = function (transaction, next) { axios({ diff --git a/Exchange/wrappers/coss.js b/Exchange/wrappers/coss.js new file mode 100644 index 000000000..346655af5 --- /dev/null +++ b/Exchange/wrappers/coss.js @@ -0,0 +1,340 @@ +// Source: https://github.com/coss-exchange/trading-api-wrapper-node-js/blob/master/index.js +// Documentation: https://api.coss.io/v1/spec + +const request = require('superagent'); +const querystring = require('querystring'); +const HttpMethod = { POST: 1, GET: 2, DELETE: 3 }; +const util = require('util'); + +const HOST_URL = "https://trade.coss.io/c/api/v1"; +const HOST_URL2 = "https://engine.coss.io/api/v1"; +const EXCHANGE_HOST = "https://exchange.coss.io/api"; + + +//WRAPPER STARTS HERE (Commenting out stuff that coss wrote which should be part of bot.js (the actual trading bot) rather than index.js (the wrapper core functionality)) +let Coss = (keyVaultAPI) => { + + //HTTPS Private Request + async function transmit_encrypted_request(method, url, payload) { + var payload_json_str = method == HttpMethod.GET ? querystring.stringify(payload) : JSON.stringify(payload) + var sign = await transmit_payload_signature_get(payload_json_str) + var req_headers = transmit_signed_header_get(sign) + + console.log(`sending ${payload_json_str} to ${url}`) + + if (method == HttpMethod.POST) { + let response = await request.post(url).set(req_headers).send(payload_json_str) + return (response.body); + + } else if (method == HttpMethod.DELETE) { + let response = await request.delete(url).set(req_headers).send(payload_json_str) + return (response.body); + + } else if (method == HttpMethod.GET) { + let response = await request.get(url).set(req_headers).query(payload_json_str) + return (response.body); + } + + } + + function transmit_signed_header_get(sign) { + var req_headers = { + 'Content-Type': 'application/json', + 'X-Requested-With': 'XMLHttpRequest', + 'Authorization': sign.Key, + 'Signature': sign.Sign, + } + return req_headers + } + + //AUTHBUILDER + async function transmit_payload_signature_get(payload_json_str) { + const signTransaction = util.promisify(keyVaultAPI.signTransaction) + return await signTransaction(payload_json_str) + } + + //HTTPS Public Request + async function publicRequest(url) { + let response = await request.get(url) + return response.body; + } + + + return { + //PLACE LIMIT ORDER + placeLimitOrder: async (params = {}) => { + if (!params.Symbol) { + return Promise.reject("placeLimitOrder(), You must supply a valid trading pair Symbol, e.g. 'COSS_ETH'!"); + } else if (params.Symbol && typeof params.Symbol !== 'string') { + return Promise.reject("placeLimitOrder(), You must supply a valid trading pair Symbol as a string, e.g. 'COSS_ETH'!"); + } else if (!params.Side) { + return Promise.reject("placeLimitOrder(), You must supply a valid Side, e.g. 'BUY' or 'SELL'!"); + } else if (params.Side && params.Side !== 'Buy' && params.Side !== 'Sell') { + return Promise.reject("placeLimitOrder(), You must supply a valid Side, e.g. 'BUY' or 'SELL'!"); + } else if (!params.Price || !params.Amount) { + return Promise.reject("placeLimitOrder(), You must supply a valid Price and Amount, e.g. Price: '0.00000034' or Amount: '123.00000000'!"); + //} else if (typeof params.Price !== 'number' || typeof params.Amount !== 'number') { + //return Promise.reject("placeLimitOrder(), You must supply a valid Price and Amount as a number, e.g. Price: '0.00000034' or Amount: '123.00000000'!"); + } + var now = new Date().getTime() + var query_params = { + 'order_symbol': params.Symbol, + 'order_price': params.Price.toString(), + 'order_side': params.Side, + 'order_size': params.Amount.toString(), + 'type': 'limit', + 'timestamp': now, + 'recvWindow': 5000 + } + let url = HOST_URL + "/order/add"; + return transmit_encrypted_request(HttpMethod.POST, url, query_params) + }, + + //PLACE MARKET ORDER + placeMarketOrder: async (params = {}) => { + if (!params.Symbol) { + return Promise.reject("placeMarketOrder(), You must supply a valid trading pair Symbol, e.g. 'COSS_ETH'!"); + } else if (params.Symbol && typeof params.Symbol !== 'string') { + return Promise.reject("placeMarketOrder(), You must supply a valid trading pair Symbol as a string, e.g. 'COSS_ETH'!"); + } else if (!params.Side) { + return Promise.reject("placeMarketOrder(), You must supply a valid Side, e.g. 'BUY' or 'SELL'!"); + } else if (params.Side && params.Side !== 'Buy' && params.Side !== 'Sell') { + return Promise.reject("placeMarketOrder(), You must supply a valid Side, e.g. 'BUY' or 'SELL'!"); + } else if (!params.Amount) { + return Promise.reject("placeMarketOrder(), You must supply a valid Amount, e.g. Amount: '123.00000000'!"); + } else if (typeof params.Amount !== 'number') { + return Promise.reject("placeMarketOrder(), You must supply a valid Amount as a number, e.g. Amount: '123.00000000'!"); + } + var now = new Date().getTime() + var query_params = { + 'order_symbol': params.Symbol, + 'order_side': params.Side, + 'order_size': params.Amount.toString(), + 'type': 'market', + 'timestamp': now, + 'recvWindow': 5000 + } + let url = HOST_URL + "/order/add"; + return transmit_encrypted_request(HttpMethod.POST, url, query_params) + }, + + //Get Account Balances + getAccountBalances: async (params = {}) => { + var now = new Date().getTime() + var query_params = { + 'recvWindow': 5000, + 'timestamp': now + } + let url = HOST_URL + "/account/balances"; + return transmit_encrypted_request(HttpMethod.GET, url, query_params) + }, + + //Get Account Details + getAccountDetails: async (params = {}) => { + var now = new Date().getTime() + var query_params = { + 'recvWindow': 5000, + 'timestamp': now + } + let url = HOST_URL + "/account/details"; + return transmit_encrypted_request(HttpMethod.GET, url, query_params) + }, + + //CANCEL ORDER BY ID # + cancelOrder: async (params = {}) => { + if (!params.ID) { + return Promise.reject("cancelOrder(), You must supply a valid order_ID to cancel, e.g. '9e5ae4dd-3369-401d-81f5-dff985e1c4e7'!"); + } else if (params.ID && typeof params.ID !== 'string') { + return Promise.reject("cancelOrder(), You must supply a valid order_ID to cancel as a string, e.g. '9e5ae4dd-3369-401d-81f5-dff985e1c4e7'!"); + } else if (!params.Symbol) { + return Promise.reject("cancelOrder(), You must supply a valid trading pair Symbol, e.g. 'COSS_ETH'!"); + } else if (params.Symbol && typeof params.Symbol !== 'string') { + return Promise.reject("cancelOrder(), You must supply a valid trading pair Symbol as a string, e.g. 'COSS_ETH'!"); + } + + var now = new Date().getTime() + var query_params = { + 'order_id': params.ID, + 'order_symbol': params.Symbol, + 'timestamp': now, + 'recvWindow': 5000 + } + let url = HOST_URL + "/order/cancel"; + return transmit_encrypted_request(HttpMethod.DELETE, url, query_params) + }, + + //GET ORDER DETAILS + getOrderDetails: async (params = {}) => { + if (!params.ID) { + return Promise.reject("getOrderDetails(), You must supply a valid order_ID to cancel, e.g. '9e5ae4dd-3369-401d-81f5-dff985e1c4e7'!"); + } else if (params.ID && typeof params.ID !== 'string') { + return Promise.reject("getOrderDetails(), You must supply a valid order_ID to cancel as a string, e.g. '9e5ae4dd-3369-401d-81f5-dff985e1c4e7'!"); + } + + var now = new Date().getTime() + var query_params = { + 'order_id': params.ID, + 'timestamp': now, + 'recvWindow': 5000 + } + let url = HOST_URL + "/order/details"; + return transmit_encrypted_request(HttpMethod.POST, url, query_params) + }, + + //GET OPEN ORDERS + getOpenOrders: async (params = {}) => { + if (!params.Limit) { + return Promise.reject("getOpenOrders(), You must supply a valid Limit for your open orders, e.g. '10'!"); + } else if (params.Limit && typeof params.Limit !== 'number') { + return Promise.reject("getOpenOrders(), You must supply a valid Limit as a number for your open orders, e.g. '10'!"); + } else if (!params.Symbol) { + return Promise.reject("getOpenOrders(), You must supply a valid trading pair Symbol, e.g. 'COSS_ETH'!"); + } else if (params.Symbol && typeof params.Symbol !== 'string') { + return Promise.reject("getOpenOrders(), You must supply a valid trading pair Symbol as a string, e.g. 'COSS_ETH'!"); + } + + var now = new Date().getTime() + var query_params = { + 'limit': params.Limit.toString(), + 'page': 0, + 'symbol': params.Symbol, + 'timestamp': now, + 'recvWindow': 5000 + } + let url = HOST_URL + "/order/list/open"; + return transmit_encrypted_request(HttpMethod.POST, url, query_params) + }, + + //GET COMPLETED ORDERS + getCompletedOrders: async (params = {}) => { + if (!params.Limit) { + return Promise.reject("getCompletedOrders(), You must supply a valid Limit for your open orders, e.g. '10'!"); + } else if (params.Limit && typeof params.Limit !== 'number') { + return Promise.reject("getCompletedOrders(), You must supply a valid Limit as a number for your open orders, e.g. '10'!"); + } else if (!params.Symbol) { + return Promise.reject("getCompletedOrders(), You must supply a valid trading pair Symbol, e.g. 'COSS_ETH'!"); + } else if (params.Symbol && typeof params.Symbol !== 'string') { + return Promise.reject("getCompletedOrders(), You must supply a valid trading pair Symbol as a string, e.g. 'COSS_ETH'!"); + } + + var now = new Date().getTime() + var query_params = { + 'limit': params.Limit.toString(), + 'page': 0, + 'symbol': params.Symbol, + 'timestamp': now, + 'recvWindow': 5000 + } + let url = HOST_URL + "/order/list/completed"; + return transmit_encrypted_request(HttpMethod.POST, url, query_params) + }, + + //GET ALL USER ORDERS + getAllOrders: async (params = {}) => { + if (!params.Limit) { + return Promise.reject("getAllOrders(), You must supply a valid Limit for your open orders, e.g. '10'!"); + } else if (params.Limit && typeof params.Limit !== 'number') { + return Promise.reject("getAllOrders(), You must supply a valid Limit as a number for your open orders, e.g. '10'!"); + } else if (!params.Symbol) { + return Promise.reject("getAllOrders(), You must supply a valid trading pair Symbol, e.g. 'COSS_ETH'!"); + } else if (params.Symbol && typeof params.Symbol !== 'string') { + return Promise.reject("getAllOrders(), You must supply a valid trading pair Symbol as a string, e.g. 'COSS_ETH'!"); + } else if (!params.ID) { + return Promise.reject("getAllOrders(), You must supply a valid account ID"); + } else if (params.ID && typeof params.ID !== 'string') { + return Promise.reject("getAllOrders(), You must supply a valid account ID as a string"); + } + + var now = new Date().getTime() + var query_params = { + 'symbol': params.Symbol, + 'from_id': params.ACCT_ID, + 'limit': params.Limit, + 'timestamp': now, + 'recvWindow': 5000 + } + let url = HOST_URL + "/order/list/all"; + return transmit_encrypted_request(HttpMethod.POST, url, query_params) + }, + + + //Public API Calls (don't need to be signed) + //get Market Price + getMarketPrice: async (params = {}) => { + if (!params.Symbol) { + return Promise.reject("getMarketPrice(), You must supply a valid trading pair Symbol, e.g. 'COSS_ETH'!"); + } else if (params.Symbol && typeof params.Symbol !== 'string') { + return Promise.reject("getMarketPrice(), You must supply a valid trading pair Symbol as a string, e.g. 'COSS_ETH'!"); + } + + let url = HOST_URL + "/market-price/" + '?symbol=' + params.Symbol; + + + return publicRequest(url); + }, + + //get Market Price + getPairDepth: async (params = {}) => { + if (!params.Symbol) { + return Promise.reject("getPairDepth(), You must supply a valid trading pair Symbol, e.g. 'COSS_ETH'!"); + } else if (params.Symbol && typeof params.Symbol !== 'string') { + return Promise.reject("getPairDepth(), You must supply a valid trading pair Symbol as a string, e.g. 'COSS_ETH'!"); + } + console.log(HOST_URL2 + "/dp" + '?symbol=' + params.Symbol); + let url = HOST_URL2 + "/dp" + '?symbol=' + params.Symbol; + + + return publicRequest(url); + }, + + //get Market Price + getMarketSides: async (params = {}) => { + if (!params.Symbol) { + return Promise.reject("getMarketSides(), You must supply a valid trading pair Symbol, e.g. 'COSS_ETH'!"); + } else if (params.Symbol && typeof params.Symbol !== 'string') { + return Promise.reject("getMarketSides(), You must supply a valid trading pair Symbol as a string, e.g. 'COSS_ETH'!"); + } + console.log(HOST_URL2 + "/dp" + '?symbol=' + params.Symbol); + let url = HOST_URL2 + "/dp" + '?symbol=' + params.Symbol; + + let pairDepth = await publicRequest(url); + let marketSides = [[pairDepth.bids[0][0], pairDepth.bids[0][1]], [pairDepth.asks[0][0], pairDepth.asks[0][1]]]; + + return (marketSides) + }, + + //get Exchange Info + getExchangeInfo: async () => { + console.log(HOST_URL + "/exchange-info"); + let url = HOST_URL + "/exchange-info"; + + return publicRequest(url); + }, + + //get Market Summary (NOT WORKING ATM) + getMarketSummary: async (params = {}) => { + if (!params.Symbol) { + return Promise.reject("getMarketSummary(), You must supply a valid trading pair Symbol, e.g. 'COSS_ETH'!"); + } else if (params.Symbol && typeof params.Symbol !== 'string') { + return Promise.reject("getMarketSummary(), You must supply a valid trading pair Symbol as a string, e.g. 'COSS_ETH'!"); + } + console.log(EXCHANGE_HOST + "/getmarketsummaries/" + '?symbol=' + params.Symbol); + let url = EXCHANGE_HOST + "/getmarketsummaries/" + '?symbol=' + params.Symbol; + + return publicRequest(url); + }, + + getTradeHistory: async (params = {}) => { + if (!params.Symbol) { + return Promise.reject("getTradeHistory(), You must supply a valid trading pair Symbol, e.g. 'COSS_ETH'!"); + } else if (params.Symbol && typeof params.Symbol !== 'string') { + return Promise.reject("getTradeHistory(), You must supply a valid trading pair Symbol as a string, e.g. 'COSS_ETH'!"); + } + console.log(HOST_URL2 + "/ht" + '?symbol=' + params.Symbol); + let url = HOST_URL2 + "/ht" + '?symbol=' + params.Symbol; + + return publicRequest(url); + } + } +}; +module.exports = exports = Coss; diff --git a/Exchange/wrappers/cossClient.js b/Exchange/wrappers/cossClient.js new file mode 100644 index 000000000..3845232a6 --- /dev/null +++ b/Exchange/wrappers/cossClient.js @@ -0,0 +1,178 @@ +exports.newAPIClient = function newAPIClient(keyVaultAPI, logger) { + const Coss = require("./coss"); + const exchangeProperties = require('./cossProperties.json'); + let API = Coss(keyVaultAPI); + + let thisObject = { + getTicker: getTicker, + getOpenPositions: getOpenPositions, + getExecutedTrades: getExecutedTrades, + buy: buy, + sell: sell, + movePosition: movePosition, + getPublicTradeHistory: getPublicTradeHistory, + getExchangeProperties: getExchangeProperties, + isValidLot: isValidLot + }; + + return thisObject; + + function joinCurrencies(currencyA, currencyB) { + // If only one arg, then return the first + if (typeof currencyB !== 'string') { + return currencyA; + } + + return currencyA + '_' + currencyB; + } + + + /* + * Returns the properties for this exchange + */ + function getExchangeProperties() { + return exchangeProperties; + } + + /* + * Returns the price for a given pair of assets. + * The object returned is an array of trades: + * ticker = { + * bid, Number + * ask, Number + * last Number + * }; + */ + async function getTicker(pMarket, callBack) { + + let params = {} + params.Symbol = joinCurrencies(pMarket.assetB, pMarket.assetA) + try { + var response = await API.getPairDepth(params) + let ticker = { + bid: Number(response.bids[0][0]), + ask: Number(response.asks[0][0]), + last: Number((response.bids[0][0] + response.asks[0][0]) / 2) // TODO Pending review + }; + + callBack(global.DEFAULT_OK_RESPONSE.result, ticker) + } catch (error) { + callBack(global.DEFAULT_FAIL_RESPONSE.result) + } + } + + /* + * Returns the open positions ath the exchange for a given market and user account. + * The object returned is an array of positions: + * position = { + * id, + * type, + * rate, Number + * amountA, Number + * amountB, Number + * fee, (not required) Number + * datetime + * }; + */ + function getOpenPositions(pMarket, callBack) { + // Not implemented yet + callBack(global.DEFAULT_OK_RESPONSE) + } + + /* + * Returns the trades for a given order number. + * The object returned is an array of positions: + * position = { + * id, + * type, + * rate, Number + * amountA, Number + * amountB, Number + * fee, Number + * datetime + * }; + */ + function getExecutedTrades(pPositionId, callBack) { + // Not implemented yet + callBack(global.DEFAULT_OK_RESPONSE) + } + + /* + * Creates a new buy order. + * The orderNumber is returned. String + */ + function buy(pCurrencyA, pCurrencyB, pRate, pAmount, callBack) { + // Not implemented yet + callBack(global.DEFAULT_OK_RESPONSE) + } + + /* + * Creates a new sell order. + * The orderNumber is returned. String + */ + function sell(pCurrencyA, pCurrencyB, pRate, pAmount, callBack) { + // Not implemented yet + callBack(global.DEFAULT_OK_RESPONSE) + } + + /* + * Move an existing position to the new rate. + * The orderNumber is returned. String + */ + function movePosition(pPosition, pNewRate, pNewAmountB, callBack) { + // Not implemented yet + callBack(global.DEFAULT_OK_RESPONSE) + } + + /* + * Returns all the trade history from the Exchange since startTime to endTime orderd by tradeId. + * It's possible that the exchange doesn't support this method. + * The object returned is an array of trades: + * trade = { + * tradeID, String + * globalTradeID, String + * type, String + * rate, Number + * amountA, Number + * amountB, Number + * date Date + * }; + */ + async function getPublicTradeHistory(assetA, assetB, startTime, endTime, callBack) { + + let params = {} + params.Symbol = joinCurrencies(assetB, assetA) + try { + let trades = [] + var response = await API.getTradeHistory(params); + for (let i = 0; i < response.history.length; i++) { + let record = response.history[i] + let type + if (record.isBuyerMaker) { + type = "sell" + } else { + type = "buy" + } + + let trade = { + tradeID: record.id, + globalTradeID: record.id, + type: type, + rate: Number(record.price), + amount: Number(record.qty), + total: Number(record.price) * Number(record.qty), + date: new Date(record.time) + } + trades.push(trade); + } + + callBack(global.DEFAULT_OK_RESPONSE.result, trades); + } catch (error) { + callBack(global.DEFAULT_FAIL_RESPONSE.result); + } + } + + function isValidLot(price, amount) { + return amount * price >= 0.0001; + } +} diff --git a/Exchange/wrappers/cossProperties.json b/Exchange/wrappers/cossProperties.json new file mode 100644 index 000000000..310e7b119 --- /dev/null +++ b/Exchange/wrappers/cossProperties.json @@ -0,0 +1,23 @@ +{ + "currencies": [ + "BTC", + "USDT" + ], + "assets": [ + "BTC", + "USDT" + ], + "markets": [ + { + "pair": [ + "BTC", + "USDT" + ], + "maxDecimals": 5, + "minimalOrder": { + "amount": 0.0001, + "unit": "asset" + } + } + ] +} diff --git a/ExtractionBotProcessMainLoop.js b/ExtractionBotProcessMainLoop.js index 914d95a27..db8f5b7c7 100644 --- a/ExtractionBotProcessMainLoop.js +++ b/ExtractionBotProcessMainLoop.js @@ -13,7 +13,7 @@ const DEBUG_MODULE = require(ROOT_DIR + 'DebugLog'); let logger; // We need this here in order for the loopHealth function to work and be able to rescue the loop when it gets in trouble. - let nextLoopTimeoutHandle; + let nextLoopTimeoutHandle; let checkLoopHealthHandle; let thisObject = { @@ -22,7 +22,7 @@ }; let processConfig; - let UI_COMMANDS; + let UI_COMMANDS; return thisObject; @@ -47,7 +47,7 @@ if (err.result === global.DEFAULT_OK_RESPONSE.result) { let filePath; - + if (global.RUN_AS_TEAM) { filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo + "/" + pProcessConfig.name; // DevTeams bots only are run at the cloud. } else { @@ -71,7 +71,7 @@ USER_BOT_MODULE = pMODULE; filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo; - + cloudRequire.downloadCommons(cloudStorage, filePath, onCommonsDownloaded); function onCommonsDownloaded(err, pMODULE) { @@ -105,7 +105,7 @@ try { if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, "[INFO] run -> Entering function."); } - bot.enableCheckLoopHealth = true; + bot.enableCheckLoopHealth = true; let fixedTimeLoopIntervalHandle; @@ -246,7 +246,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeExchangeAPI -> Entering function."); } - exchangeAPI = EXCHANGE_API.newExchangeAPI(logger); + exchangeAPI = EXCHANGE_API.newExchangeAPI(logger, process.env.EXCHANGE_NAME); exchangeAPI.initialize(onInizialized); @@ -591,7 +591,7 @@ logger.persist(); return; } else { - if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.normalWaitTime / 1000) + " seconds."); } + if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> loopControl -> Restarting Loop in " + (processConfig.normalWaitTime / 1000) + " seconds."); } checkLoopHealthHandle = setTimeout(checkLoopHealth, processConfig.normalWaitTime * 5, bot.loopCounter); nextLoopTimeoutHandle = setTimeout(loop, processConfig.normalWaitTime); logger.persist(); @@ -686,7 +686,7 @@ if (err.result === global.DEFAULT_OK_RESPONSE.result) { let filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud. - + let fileName = "this.config.json"; cloudStorage.getTextFile(filePath, fileName, onFileReceived); @@ -695,7 +695,7 @@ if (err.result !== global.DEFAULT_OK_RESPONSE.result) { - /* + /* If for any reason this config file cannot be read, we are not going to abort the loop for that. Instead we are going to assume that there are no instructions to stop and we will keep the show running. */ diff --git a/TradingBotProcessMainLoop.js b/TradingBotProcessMainLoop.js index 14ad87b49..ac051348f 100644 --- a/TradingBotProcessMainLoop.js +++ b/TradingBotProcessMainLoop.js @@ -90,7 +90,7 @@ USER_BOT_MODULE = pMODULE; filePath = global.DEV_TEAM + "/" + "bots" + "/" + bot.repo; - + cloudRequire.downloadCommons(cloudStorage, filePath, onCommonsDownloaded); function onCommonsDownloaded(err, pMODULE) { @@ -598,7 +598,7 @@ if (FULL_LOG === true) { logger.write(MODULE_NAME, "[INFO] run -> loop -> initializeExchangeAPI -> Entering function."); } - exchangeAPI = EXCHANGE_API.newExchangeAPI(logger); + exchangeAPI = EXCHANGE_API.newExchangeAPI(logger, process.env.EXCHANGE_NAME); exchangeAPI.initialize(onInizialized); @@ -1113,7 +1113,7 @@ if (err.result === global.DEFAULT_OK_RESPONSE.result) { let filePath = global.DEV_TEAM + "/" + "AACloud"; // DevTeams bots only are run at the cloud. - + let fileName = "this.config.json"; cloudStorage.getTextFile(filePath, fileName, onFileReceived);