Files
Superalgos/TaskServer/LowFrequencyTrading/ExchangeAPI.js
T

204 lines
9.1 KiB
JavaScript

exports.newExchangeAPI = function (processIndex, bot, logger) {
let MODULE_NAME = "Exchange API";
let thisObject = {
getOrder: getOrder,
createOrder: createOrder,
cancelOrder: cancelOrder,
initialize: initialize,
finalize: finalize
};
let tradingSystem
let exchangeId
let options = {}
let exchange
const ccxt = require('ccxt')
return thisObject;
function initialize() {
tradingSystem = bot.simulationState.tradingSystem
exchangeId = TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.parentNode.parentNode.name.toLowerCase()
let key
let secret
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.keyReference !== undefined) {
if (TS.projects.superalgos.globals.taskConstants.TASK_NODE.keyReference.referenceParent !== undefined) {
key = TS.projects.superalgos.globals.taskConstants.TASK_NODE.keyReference.referenceParent.config.codeName
secret = TS.projects.superalgos.globals.taskConstants.TASK_NODE.keyReference.referenceParent.config.secret
}
}
const exchangeClass = ccxt[exchangeId]
const exchangeConstructorParams = {
'apiKey': key,
'secret': secret,
'timeout': 30000,
'enableRateLimit': true,
verbose: false,
'adjustForTimeDifference': true,
options: options
}
exchange = new exchangeClass(exchangeConstructorParams)
}
function finalize() {
tradingSystem = undefined
exchangeId = undefined
options = undefined
exchange = undefined
}
async function getOrder(tradingSystemOrder, tradingEngineOrder) {
let orderId = tradingEngineOrder.exchangeId.value
const symbol = TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName
/* Basic Logging */
logInfo("getOrder -> orderId = " + orderId)
logInfo("getOrder -> symbol = " + symbol)
/* Basic Validations */
if (exchange.has['fetchOrder'] === false) {
logError("getOrder -> Exchange does not support fetchOrder command.");
return
}
try {
let order = await exchange.fetchOrder(orderId, symbol)
logInfo("getOrder -> Response from the Exchange: " + JSON.stringify(order));
return order
} catch (err) {
tradingSystem.errors.push([tradingSystemOrder.id, "getOrder -> Error = " + err.message])
logError("getOrder -> Error = " + err.message);
}
}
async function createOrder(tradingSystemOrder, tradingEngineOrder) {
let price = tradingEngineOrder.rate.value // CCXT: how much quote currency you are willing to pay for a trade lot of base currency (for limit orders only)
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 = TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName // CCXT: a string literal symbol of the market you wish to trade on, like BTC/USD, ZEC/ETH, DOGE/DASH, etc
let amount = tradingEngineOrder.orderBaseAsset.size.value // CCXT: how much of currency you want to trade, in Base Asset.
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 -> type = " + type);
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 {
let order = await (exchange.createOrder(symbol, type, side, amount, price))
logInfo("createOrder -> Response from the Exchange: " + JSON.stringify(order));
return order.id
} catch (err) {
tradingSystem.errors.push([tradingSystemOrder.id, "createOrder -> Error = " + err.message])
logError("createOrder -> Error = " + err.message)
logError("createOrder -> symbol = " + symbol);
logError("createOrder -> side = " + side);
logError("createOrder -> type = " + type);
logError("createOrder -> amount = " + amount);
logError("createOrder -> price = " + price);
if (
err.message.indexOf('API-key format invalid') >= 0 ||
err.message.indexOf('Invalid API-key, IP, or permissions for action.') >= 0 ||
err.message.indexOf('"code":-2015') >= 0
) {
logError ('The exchange says the API key provided is not good or it is not in the correct format. This is what you are using:')
errorFooter()
}
if (
err.message.indexOf('Signature for this request is not valid.') >= 0 ||
err.message.indexOf('"code":-1022') >= 0
) {
logError ('The exchange says the secret provided is not good, incorrect or not in the correct format. This is what you are using:')
errorFooter()
}
function errorFooter(){
logError ('key: ->' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.keyReference.referenceParent.config.codeName + '<-')
logError ('secret: ->' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.keyReference.referenceParent.config.secret + '<-')
logError ('key.length:' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.keyReference.referenceParent.config.codeName.length )
logError ('secret.length:' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.keyReference.referenceParent.config.secret.length )
logError ('Double check that you copied the key at the codeName property and the secret at secret property without bringing any invisible caracter from the exchange web site, or leaving any character from the sample text. Also check that the keys are not disabled at the exchange ot that they are not restricted by IP.')
logError ('As a remainder. Binance key and secret are 64 bytes in lenght each one. ' )
}
}
}
async function cancelOrder(tradingSystemOrder, tradingEngineOrder) {
let orderId = tradingEngineOrder.exchangeId.value
/* Basic Logging */
logInfo("cancelOrder -> Entering function. orderId = " + orderId);
const symbol = TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.baseAsset.referenceParent.config.codeName + '/' + TS.projects.superalgos.globals.taskConstants.TASK_NODE.parentNode.parentNode.parentNode.referenceParent.quotedAsset.referenceParent.config.codeName
/* Basic Validations */
if (exchange.has['fetchOrder'] === false) {
logError("cancelOrder -> Exchange does not support fetchOrder command.");
return
}
try {
let order = await exchange.cancelOrder(orderId, symbol)
logInfo("cancelOrder -> Response from the Exchange: " + JSON.stringify(order));
return true
} catch (err) {
tradingSystem.errors.push([tradingSystemOrder.id, "cancelOrder -> Error = " + err.message])
logError("cancelOrder -> Error = " + err.message);
}
}
function logInfo(message) {
logger.write(MODULE_NAME, '[INFO] ' + message)
}
function logError(message) {
logger.write(MODULE_NAME, '[ERROR] ' + message)
}
};