Merge pull request #61 from AAVikings/master
Adding basic Coss exchange integration
This commit is contained in:
6 files changed
+563
-16
No files matched your search
+10
-4
@@ -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({
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"currencies": [
|
||||
"BTC",
|
||||
"USDT"
|
||||
],
|
||||
"assets": [
|
||||
"BTC",
|
||||
"USDT"
|
||||
],
|
||||
"markets": [
|
||||
{
|
||||
"pair": [
|
||||
"BTC",
|
||||
"USDT"
|
||||
],
|
||||
"maxDecimals": 5,
|
||||
"minimalOrder": {
|
||||
"amount": 0.0001,
|
||||
"unit": "asset"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user