One of the intended uses of our REST API is to create automated trading bots that interact with our markets and accounts.
While trading bots come in an almost endless variety, they all share similar API integration characteristics, and all perform the following common tasks:
- retrieving market data (ticker, order book etc.)
- making trading decisions (based upon the market data, or indicators derived from the market data)
- placing/cancelling orders
Our REST API provides all of the functionality needed to implement a full featured trading bot, but knowing how to combine the different aspects of our API can be difficult, hence the following trading bot code is provided as an example.
The example code implements an indicator based trading bot (specifically a 80/20 over bought, over sold RSI, with trading decisions based upon a 1 minute slope change), and shows how to integrate the market data, decision making, and trading aspects of a trading bot successfully.
Example Code (NodeJs)
The trading bot code is a single NodeJs file and integrates directly with our API. All configuration (API key, currency pair, indicator, order type, leverage etc.) is contained within the code for ease of reference.
The example code can be viewed below and can also be downloaded as a .js file here.
/*
* IMPORT LIBRARIES
*/
const crypto = require('crypto');
const axios = require("axios");
const { COPYFILE_FICLONE } = require('constants');
const { log } = console;
/*
* DEFINE FUNCTIONS
*/
function GetPublicApiJson(endPoint, parameters) {
return__awaiter(this, void 0, void 0, function* () {
constbase = "https://api.kraken.com";
constpath = "/0/public/";
constapiEndpointFullURL = base + path + endPoint + '?' + parameters;
constresponse = yieldaxios.get(apiEndpointFullURL);
constrawStringJSON = JSON.stringify(response.data);
returnresponse.data.result;
});
}
function GetPrivateApiJson(endPoint, paramters) {
return__awaiter(this, void 0, void 0, function* () {
constapiPublicKey = "YOUR PUBLIC KEY";
constapiPrivateKey = "YOUR PRIVATE KEY";
constbase = "https://api.kraken.com";
constpath = "/0/private/";
constapiEndpointFullURL = base + path + endPoint;
constnonce = Date.now().toString();
constapiPostBodyData = "nonce=" + nonce + "&" + paramters;
constapiPost = nonce + apiPostBodyData;
constapiEndpointPath = path + endPoint;
constsecret = Buffer.from(apiPrivateKey, 'base64');
constsha256 =crypto.createHash('sha256');
consthmac512 =crypto.createHmac('sha512', secret);
consthash256 =sha256.update(apiPost).digest('binary');
constsignatureString =hmac512.update(apiEndpointPath + hash256, 'binary').digest('base64');
consthttpOptions = {
headers: { 'API-Key': apiPublicKey, 'API-Sign': signatureString }
};
constresponse = yieldaxios.post(apiEndpointFullURL, apiPostBodyData, httpOptions);
constrawStringJSON = JSON.stringify(response.data);
leterrors =response.data.error;
if (errors.length > 0) {
log('ERROR:');
log(response.data.error[0]);
}
returnresponse.data.result;
});
}
/*
* DEFINE VARIABLES
*/
let totalNumOfRuns = 1;
const timeFrame = 1; //Minutes
const RSILength = 14;
const RSIOverBought = 80;
const RSIOverSold = 20;
function timedLoop(func, delay) {
func();
setTimeout(() =>timedLoop(func, delay), delay);
}
timedLoop(() => __awaiter(this, void 0, void 0, function* () {
log(`Bot Run Number ${totalNumOfRuns} at `, Date.now().toString());
log('');
totalNumOfRuns = totalNumOfRuns + 1;
log(`Getting Candle Data, ${timeFrame} Minute Resolution`);
log('');
letcandles = yieldGetPublicApiJson("OHLC",`pair=XETHXXBT&invterval=${timeFrame}`);
candles = candles['XETHXXBT'];
//https://www.macroption.com/rsi-calculation/
lettotalPriceUp = 0; //sum of up candles
lettotalPriceDown = 0; //sum of down candles
//Ignore the last candle because it's not closed
for (letindex = RSILength; index > 0; index--) {
constclose = candles[index][4];
constprevClose = candles[index + 1][4];
if (close > prevClose) {
//UP
totalPriceUp = totalPriceUp + (close - prevClose);
}
elseif (close < prevClose) {
//DOWN
totalPriceDown = totalPriceDown + (prevClose - close);
}
}
constbalances = yieldGetPrivateApiJson("Balance", "");
constbtcBalance = balances['XXBT'];
constethBalance = balances['XETH'];
log('Current Account Balance:');
log(balances);
log('');
log('Current BTC Balance:');
log(btcBalance);
log('');
log('Current ETH Balance:');
log(ethBalance);
log('');
//simple moving average
letaverageUp = totalPriceUp / RSILength;
letaverageDown = totalPriceDown / RSILength;
letrsi = 100 - 100 / (1 + averageUp / averageDown);
log('Current RSI:', rsi);
log(`RSI Over Sold Level (Buy ETH): ${RSIOverSold}`);
log(`RSI Over Bought Level (Sell BTC): ${RSIOverBought}`);
log(``);
if (rsi < RSIOverSold) {
//buy eth if oversold
log('RSI Is Over Sold!');
//convert BTC to ETH at current price
//Using 95% of funds
constethToBuy = (btcBalance / candles[0][4]) * .95;
constbuyAddOrderJSON = yieldGetPrivateApiJson("AddOrder",`pair=XETHXXBT&type=buy&ordertype=market&volume=${ethToBuy}`);
log(`Buying ${ethToBuy} ETH with BTC`);
log('');
log('Buy Order Result');
log(buyAddOrderJSON);
log('');
}
elseif (rsi > RSIOverBought) {
//sell btc if overbought
log('RSI Is Over Bought!');
//Use 95% of funds
constbtcToBuy = ethBalance * .95;
constsellAddOrderJSON = yieldGetPrivateApiJson("AddOrder",`pair=XETHXXBT&type=sell&ordertype=market&volume=${btcToBuy}`);
log(`Selling ${btcToBuy} ETH for BTC`);
log('');
log('Sell Order Result');
log(sellAddOrderJSON);
log('');
}
else {
log('RSI Is Not Over Sold Or Over Bought - HODL & Chill :)');
log('');
}
}), timeFrame * 60000);
//# sourceMappingURL=app.js.map