diff --git a/ExchangeAPI.js b/LowFrequencyTrading/ExchangeAPI.js similarity index 57% rename from ExchangeAPI.js rename to LowFrequencyTrading/ExchangeAPI.js index 617b5a5a8..437b52665 100644 --- a/ExchangeAPI.js +++ b/LowFrequencyTrading/ExchangeAPI.js @@ -2,18 +2,19 @@ let MODULE_NAME = "Exchange API"; let LOG_INFO = true; - let apiClient; let bot = BOT let thisObject = { - initialize: initialize, getTicker: getTicker, getOpenOrders: getOpenOrders, getOrder: getOrder, createOrder: createOrder, - getMaxDecimalPositions: getMaxDecimalPositions + initialize: initialize, + finalize: finalize }; + let tradingSystem + let exchangeId let options = {} let exchange @@ -23,10 +24,12 @@ return thisObject; function initialize() { + tradingSystem = bot.simulationState.tradingSystem + exchangeId = bot.exchange.toLowerCase() - let key = process.env.KEY - let secret = process.env.SECRET + let key = bot.KEY + let secret = bot.SECRET if (key === "undefined") { key = undefined } if (secret === "undefined") { secret = undefined } @@ -43,11 +46,14 @@ exchange = new exchangeClass(exchangeConstructorParams) } - function getMaxDecimalPositions() { - return 8 + function finalize() { + tradingSystem = undefined + exchangeId = undefined + options = undefined + exchange = undefined } - async function getTicker(market, callBackFunction) { + async function getTicker(callBackFunction) { try { logInfo("getTicker -> Entering function."); const symbol = bot.market.baseAsset + '/' + bot.market.quotedAsset @@ -108,37 +114,60 @@ } } - async function createOrder(market, side, price, cost, amount, callBackFunction) { + async function createOrder(tradingSystemOrder, tradingEngineOrder) { + + let price = tradingEngineOrder.rate // CCXT: how much quote currency you are willing to pay for a trade lot of base currency (for limit orders only) + let amount = tradingEngineOrder.size // CCXT: how much of currency you want to trade + let type // CCXT: a string literal type of order, ccxt currently unifies market and limit orders only + let side // CCXT: a string literal for the direction of your order, buy or sell + let symbol = bot.market.baseAsset + '/' + bot.market.quotedAsset // CCXT: a string literal symbol of the market you wish to trade on, like BTC/USD, ZEC/ETH, DOGE/DASH, etc + + switch (tradingSystemOrder.type) { + case 'Market Buy Order': { + type = 'market' + side = 'buy' + break + } + case 'Market Sell Order': { + type = 'market' + side = 'sell' + break + } + case 'Limit Buy Order': { + type = 'limit' + side = 'buy' + break + } + case 'Limit Sell Order': { + type = 'limit' + side = 'sell' + break + } + } + + /* Basic Logging */ + logInfo("createOrder -> symbol = " + symbol); + logInfo("createOrder -> side = " + side); + logInfo("createOrder -> cost = " + cost); + logInfo("createOrder -> amount = " + amount); + logInfo("createOrder -> price = " + price); + + /* Basic Validations */ + if (side !== "buy" && side !== "sell") { + logError("createOrder -> side must be either 'buy' or 'sell'."); + return + } + if (exchange.has['createOrder'] === false) { + logError("createOrder -> Exchange does not support createOrder command."); + return + } + try { - logInfo("createOrder -> Entering function."); - - const symbol = bot.market.baseAsset + '/' + bot.market.quotedAsset - - logInfo("createOrder -> market = " + market.assetA + "_" + market.assetB); - logInfo("createOrder -> side = " + side); - logInfo("createOrder -> cost = " + cost); - logInfo("createOrder -> amount = " + amount); - logInfo("createOrder -> price = " + price); - - if (side !== "buy" && side !== "sell") { - logError("createOrder -> side must be either 'buy' or 'sell'."); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - - let type = 'market' - let order - - if (exchange.has['createOrder']) { - order = await (exchange.createOrder(symbol, type, side, amount)) - callBackFunction(global.DEFAULT_OK_RESPONSE, order) - } else { - logError("createOrder -> Exchange does not support createOrder command."); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); - } - + let order = await (exchange.createOrder(symbol, type, side, amount)) + return order.id } catch (err) { - logError("createOrder -> err = " + JSON.stringify(err.stack) || err.message); - callBackFunction(global.DEFAULT_FAIL_RESPONSE); + tradingSystem.errors.push([tradingSystemOrder.id, err.message]) + logError("getOrder -> Error = " + err.message); } } diff --git a/LowFrequencyTrading/Snapshots.js b/LowFrequencyTrading/Snapshots.js index d36073854..89c10767b 100644 --- a/LowFrequencyTrading/Snapshots.js +++ b/LowFrequencyTrading/Snapshots.js @@ -244,7 +244,7 @@ exports.newSnapshots = function newSnapshots(bot, logger) { } } } catch (err) { - tradingSystem.errors.push(nodeWithCode.id, err.message) + tradingSystem.errors.push([nodeWithCode.id, err.message]) logger.write(MODULE_NAME, '[ERROR] runSimulation -> addCodeToSnapshot -> nodeWithCode.code = ' + nodeWithCode.code) logger.write(MODULE_NAME, '[ERROR] runSimulation -> addCodeToSnapshot -> err = ' + err.stack) } diff --git a/LowFrequencyTrading/TradingSystem.js b/LowFrequencyTrading/TradingSystem.js index f85cc686e..b990c0afb 100644 --- a/LowFrequencyTrading/TradingSystem.js +++ b/LowFrequencyTrading/TradingSystem.js @@ -26,6 +26,9 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM let conditions = new Map() let formulas = new Map() + const EXCHANGE_API_MODULE = require('./ExchangeAPI.js') + let exchangeAPIModule = EXCHANGE_API_MODULE.newExchangeAPI(bot, logger) + const TRADING_STRATEGY_MODULE = require('./TradingStrategy.js') let tradingStrategyModule = TRADING_STRATEGY_MODULE.newTradingStrategy(bot, logger, tradingEngineModule) @@ -48,6 +51,7 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM tradingEngine = bot.simulationState.tradingEngine sessionParameters = bot.SESSION.parameters + exchangeAPIModule.initialize() tradingStrategyModule.initialize() tradingPositionModule.initialize() announcementsModule.initialize() @@ -56,6 +60,9 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM } function finalize() { + exchangeAPIModule.finalize() + exchangeAPIModule = undefined + tradingStrategyModule.finalize() tradingStrategyModule = undefined @@ -1166,6 +1173,9 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM if (tradingEngineOrder.size.value <= 0) { continue } + /* Place Order at the Exchange */ + if (placeOrderAtExchange(tradingSystemOrder, tradingEngineOrder) !== true) { continue } + /* Updating Episode Counters */ tradingEngine.episode.episodeCounters.orders.value++ @@ -1191,7 +1201,7 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM } } - /* Update State Orders Size */ + /* Update Stage Orders Size */ stageOrdersSize.value = stageOrdersSize.value + tradingEngineOrder.size.value stageOrdersSize.value = global.PRECISE(stageOrdersSize.value, 10) } @@ -1249,14 +1259,38 @@ exports.newTradingSystem = function newTradingSystem(bot, logger, tradingEngineM } /* Simulate Events that happens at the Exchange, if needed. */ - if (stageIsOpening === false) { - simulateExchangeEvents(tradingSystemOrder, tradingEngineOrder) - } + simulateExchangeEvents(tradingSystemOrder, tradingEngineOrder) } } } } + function placeOrderAtExchange(tradingSystemOrder, tradingEngineOrder) { + + /* Filter by Session Type */ + switch (bot.SESSION.type) { + case 'Backtesting Session': { + return true + } + case 'Live Trading Session': { + break + } + case 'Fordward Testing Session': { + break + } + case 'Paper Trading Session': { + return true + } + } + + let orderId = exchangeAPIModule.createOrder(tradingSystemOrder, tradingEngineOrder) + + if (orderId !== undefined) { + tradingEngineOrder.exchangeId.value = orderId + return true + } + } + function simulateExchangeEvents(tradingSystemOrder, tradingEngineOrder) { /* Filter by Session Type */ diff --git a/Root.js b/Root.js index cecc40636..be3cc5da9 100644 --- a/Root.js +++ b/Root.js @@ -225,18 +225,14 @@ /* Bot Type */ botConfig.type = global.TASK_NODE.bot.processes[processIndex].referenceParent.parentNode.type - /* Setting the Key to use */ - process.env.KEY = undefined - process.env.SECRET = undefined - if (botConfig.processNode) { if (botConfig.processNode.marketReference) { if (botConfig.processNode.marketReference.keyInstance !== undefined) { if (botConfig.processNode.marketReference.keyInstance.referenceParent !== undefined) { let key = botConfig.processNode.marketReference.keyInstance.referenceParent - process.env.KEY = key.config.codeName - process.env.SECRET = key.config.secret + botConfig.KEY = key.config.codeName + botConfig.SECRET = key.config.secret } } } diff --git a/Session.js b/Session.js index beedc4463..806468fea 100644 --- a/Session.js +++ b/Session.js @@ -300,7 +300,7 @@ } function startLiveTrading(message) { - if (process.env.KEY === undefined || process.env.SECRET === undefined) { // TODO Remove this from Process .env + if (bot.KEY === undefined || bot.SECRET === undefined) { if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, "[ERROR] initialize -> startLiveTrading -> Key 'codeName' or 'secret' not provided. Plese check that and try again."); } return false } @@ -311,7 +311,7 @@ } function startFordwardTesting(message) { - if (process.env.KEY === undefined || process.env.SECRET === undefined) { + if (bot.KEY === undefined || bot.SECRET === undefined) { if (FULL_LOG === true) { parentLogger.write(MODULE_NAME, "[WARN] initialize -> startFordwardTesting -> Key name or Secret not provided, not possible to run the process in Forward Testing mode."); } console.log("Key 'codeName' or 'secret' not provided. Plese check that and try again.") return false