Skip to content

Instantly share code, notes, and snippets.

@welblaud
Last active February 6, 2019 08:59
Show Gist options
  • Save welblaud/00175194481668e04f2be130d8017d18 to your computer and use it in GitHub Desktop.
Save welblaud/00175194481668e04f2be130d8017d18 to your computer and use it in GitHub Desktop.
App for trading on gate.io forex market
// newBot.js
/* ##################### MODULES ####################### */
let fetch = require( 'node-fetch' );
let fs = require( 'fs' );
let crypto = require( 'crypto' );
let querystring = require( 'querystring' );
/* ##################### CONSTANTS ####################### */
const KEY = '';
const SECRET = '';
const pairs = [ ['btc_usdt', 0.0018], ['eth_usdt', 0.028], ['etc_usdt', 1] ];
const logPath = '/home/bob/git/Gate.io/app/log/log.txt';
const MARKETINFO_URL = 'api2/1/marketinfo';
const MARKETLIST_URL = 'api2/1/marketlist';
const API_QUERY_URL = 'https://data.gate.io/';
const API_TRADE_URL = 'https://api.gate.io/';
const BUY_URL = 'api2/1/private/buy';
const SELL_URL = 'api2/1/private/sell';
const GETORDER_URL = 'api2/1/private/getOrder';
const OPENORDERS_URL = 'api2/1/private/openOrders';
const CANCELORDER_URL = 'api2/1/private/cancelOrder';
const CANCELALLORDERS_URL = 'api2/1/private/cancelAllOrders';
const TICKER_URL = 'api2/1/ticker';
const USER_AGENT = '';
/* ##################### ORDER LISTS ####################### */
let ordersBuy = [];
let ordersSell = [];
/* ################### MAKING BUSINESS ##################### */
// businessmanBot( 'eth_usdt', 0.028 )
for (pair of pairs) {
let code = pair[0];
let amount = pair[1];
businessmanBot( code, amount )
}
/* ################################################################################################# *
* +++++++++++++++++++++++++++++++++++++++++ THE BOT +++++++++++++++++++++++++++++++++++++++++++++++ *
* ################################################################################################# */
async function businessmanBot( currencyPair, amount ) {
// Čistíme log před každým cyklem.
await cleanLog();
// Nastavujeme interval na 10 vteřin
// a spouštíme bota.
setInterval( function() { doBusiness( currencyPair, amount ) }, 10000 );
}
// Hlavní funkce bota
async function doBusiness( currencyPair, amount ) {
// Získáváme info o tickeru a nastavujeme hodnoty.
let tickerInfo = await fetch( API_QUERY_URL + TICKER_URL + '/' + currencyPair, { method: 'GET', headers: { 'User-Agent': USER_AGENT } }).catch(err => console.log(err));
let tickerJSON = await tickerInfo.json();
let lowestAsk = await tickerJSON.lowestAsk;
let highestBid = await tickerJSON.highestBid;
let rate = await highestBid + 0.01;
let percentDiff = await ( lowestAsk - highestBid ) / lowestAsk * 100;
let datum = new Date();
datum = 'Čas: '
+ datum.getFullYear().toString()
+ '-' + (datum.getMonth() + 1).toString()
+ '-' + datum.getDate().toString()
+ ' ' + (datum.getHours().toString().length === 1 ? '0' + datum.getHours().toString() : datum.getHours().toString())
+ ':' + (datum.getMinutes().toString().length === 1 ? '0' + datum.getMinutes().toString() : datum.getMinutes().toString())
+ ':' + (datum.getSeconds().toString().length === 1 ? '0' + datum.getSeconds().toString() : datum.getSeconds().toString());
// Jestliže je rozdíl mezi lowestAsk a highestBid větší než 0.4, kupujeme.
if (( percentDiff !== undefined ) && ( percentDiff > 0.5 )) {
log(
'\n###########################\n'
+ '| ' + datum + ' |\n'
+ '---------------------------\n'
+ '| currencyPair: ' + currencyPair + '\n'
+ '| lowestAsk: ' + lowestAsk + '\n'
+ '| highestBid: ' + highestBid + '\n'
+ '| rate: ' + rate.toFixed(2) + '\n'
+ '| percentDiff: ' + percentDiff.toFixed(4) + '\n'
+ '---------------------------'
);
// Provádíme nákup, informace o orderu ukládáme do proměnné (buyOrder).
let buyOrder = await placeOrder ( currencyPair, rate, amount );
// Pokud je něco špatně (např. došly peníze na účtu), logujeme a zastavujeme bota.
if ( buyOrder.status !== true || buyOrder.orderNumber === undefined ) {
log( 'Něco je špatně, order nebyl umístěn: ' + buyOrder.status);
//stopTimer(intID);
} else if ( buyOrder.status === true && buyOrder.orderNumber !== undefined ) {
// Ověřujeme stav orderu.
let verifyOrder = await orderInfo( buyOrder.orderNumber, currencyPair );
// Jestliže je rozdíl mezi aktuálně zjištěnou rate (verifyOrder) a původní highestBid roven 0.01 (cent)...
if (( verifyOrder.rate !== undefined ) && (( verifyOrder.rate - highestBid ) === 0.01 )) {
// ... vše je v pořádku a informace o orderu (buyOrder) umisťujeme do seznamu pro BUY ordery.
ordersBuy.push( await buyOrder );
// Logujeme.
await log(
'\n----------------------------\n'
+ 'Order BUY umístěn: ' + buyOrder.oderNumber + '\n'
);
// Jinak...
} else {
// ... rušíme order.
await cancelOrder( buyOrder.orderNumber, currencyPair );
// Logujeme.
await log( 'Order BUY zrušen: ' + buyOrder.oderNumber + '\n' );
} // end ELSE
} else {
console.log('Došlo k jinému problému. Log ř. 124.');
}
} else if ( percentDiff === undefined ) {
log('Problém se získáním percentDiff!\n');
} // end IF/ELSE
// V tuto chvíli by měl být order v seznamu (BUY) a čekat na další akce. Pokud jsme ho rušili,
// do seznamu (BUY) zařazen nebyl.
/* ####################### BUY LOOP ###################### */
// Pro každý order zařazený do seznamu pro BUY ordery (v minulém cyklu i teď).
ordersBuy.forEach(async (buy, index) => {
// Zjišťumjeme aktuální stav orderu.
let orderState = await orderInfo( buy.orderNumber, currencyPair );
orderState = await orderState;
// Jestliže je order closed a amount byla rovna initial_amount...
if (( orderState.status === 'closed' )
&& ( orderState.amount === orderState.initial_amount )) {
// ... zjišťujeme aktuální rozdíl mezi původní zadávanou rate (pro BUY) a současnou rate.
let sellRate = lowestAsk - 0.01;
let sellPerc = ( buy.rate- sellRate ) / buy.rate * 100;
// Jestliže je rozdíl mezi oběma rate větší než 0.25 %...
if ( sellPerc > 0.25 ) {
// Prodáváme (SELL), čáska je rovna částce z informace v orderState, měla by být
// navíc rovna rate BUY orderu (jak je uvedeno v podmínce).
let sellOrder = await orderSell( currencyPair, sellRate, orderState.amount );
sellOrder = await sellOrder;
// Order hned ověřujeme.
let verifyOrder = await orderInfo( sellOrder.orderNumber, currencyPair );
verifyOrder = await verifyOrder;
// Jestliže je rozdíl mezi aktuálně zjištěnou rate (verifyOrder) a původní highestBid roven 0.01 (cent)...
if (( verifyOrder.rate - highestBid ) === 0.01 ) {
// ... zařazujeme order do seznamu (SELL) pro SELL ordery a současně mažeme
// order (BUY) ze seznamu pro BUY ordery.
ordersSell.push( await sellOrder );
ordersBuy.splice( index, 1 );
// Logujeme.
await log( 'Order SELL umístěn: ' + sellOrder.oderNumber + '\n' );
// Jinak...
} else {
// ... rušíme order (SELL).
// #### Tady je otázka, co se má stát dál [prodali jsme, ale nejso podmínky pro orderSELL]
await cancelOrder( sellOrder.orderNumber, currencyPair );
// Logujeme.
await log( 'Order SELL zrušen: ' + sellOrder.oderNumber + '\n' );
} // end ELSE
} // end IF
// Jestliže je order open (visí) a odkoupená částka je nižší než částka zamýšlená (initial_amount),
// navíc pokud z daného orderu (BUY) ještě nebyl proveden order (SELL)...
} else if (( orderState.status === 'open' )
&& ( orderState.amount < orderState.initial_amount )
&& ( buy.remainder === undefined )) {
// ... zjišťujeme aktuální rozdíl mezi původní zadávanou rate (pro BUY) a současnou rate.
let sellRate = lowestAsk - 0.01;
let sellPerc = ( buy.rate- sellRate ) / buy.rate * 100;
// Jestliže je rozdíl mezi oběma rate větší než 0.25 %...
if ( sellPerc > 0.25 ) {
// Prodáváme (SELL), čáska je rovna částce z informace v orderState,
// protože je to částka, která už byla využita (nakoupeno) [ošetření zbytku níže].
let sellOrder = await orderSell( currencyPair, rate, orderState.amount );
sellOrder = await sellOrder;
let verifyOrder = await orderInfo( sellOrder.orderNumber, currencyPair );
verifyOrder = await verifyOrder;
// Jestliže je rozdíl mezi aktuální rate a highestBid zjištěnou na začátku cyklu 0.01 (cent)...
if (( verifyOrder.rate - highestBid ) === 0.01 ) {
// ... do informace pro daný order (BUY) přidáváme informaci o převisu,
// současně zařazujeme nový order (SELL) do seznamu pro SELL ordery.
buy.remainder = orderState.initial_amount - orderState.amount;
ordersSell.push( await sellOrder );
// Logujeme.
await log( 'Order SELL umístěn: ' + sellOrder.oderNumber + '\n' );
// Jinak...
} else {
// ... rušíme order (SELL).
await cancelOrder( sellOrder.orderNumber, currencyPair );
// Logujeme.
await log( 'Order SELL zrušen: ' + sellOrder.oderNumber + '\n' );
} // end ELSE
} // end IF
// Jestliže je order open (visí) a odkopená částka je nižší než částka zamýšlená (initial_amount),
// navíc pokud už byl z daného orderu (BUY) proveden v předchozím kole order (SELL),
// k tomu ještě pokud je zbytek (převis) nevyužitý pro order (SELL) z minulého kola větší
// než zbytek (převis) současný (což znamená, že došlo k dalšímu nákupu [využití initial_amount]
// bez toho, aby se vyčerpal celý zbytek a order byl closed)...
} else if (( orderState.status === 'open' )
&& ( orderState.amount < orderState.initial_amount )
&& ( buy.remainder !== undefined )
&& ( buy.remainder > ( orderState.initial_amount - orderState.amount ))) {
// ... zjišťujeme aktuální rozdíl mezi původní zadávanou rate (pro BUY) a současnou rate.
let sellRate = lowestAsk - 0.01;
let sellPerc = ( buy.rate - sellRate ) / buy.rate * 100;
// Jestliže je rozdíl mezi oběma rate větší než 0.25 %...
if ( sellPerc > 0.25 ) {
// Prodáváme (SELL), čáska by měla odpodívat rozdílu mezi nově zjištěným
// rozdílem v částkách (amountDiff = amount vs initial_amount) a původním
// zbytkem (převisem [remainder]) pro daný order (BUY).
let sellOrder = await orderSell( currencyPair, rate, newRemainder );
sellOrder = await sellOrder;
let verifyOrder = await orderInfo( sellOrder.orderNumber, currencyPair );
verifyOrder = await verifyOrder;
let amountDiff = await orderState.initial_amount - orderState.amount;
let newRemainder = await buy.remainder - amountDiff;
buy.remainder = await newRemainder;
ordersSell.push( await sellOrder );
// Jestliže je rozdíl mezi aktuální rate a highestBid zjištěnou na začátku cyklu 0.01 (cent)...
if (( verifyOrder.rate - highestBid ) === 0.01 ) {
// ... v informacích pro daný order (BUY) aktualizujeme částku převisu,
// současně zařazujeme nový order (SELL) do seznamu pro SELL ordery.
buy.remainder = newRemainder;
ordersSell.push( await sellOrder );
// Logujeme.
await log( 'Order SELL umístěn: ' + sellOrder.oderNumber + '\n' );
// Jinak...
} else {
// ... rušíme order (SELL).
await cancelOrder( sellOrder.orderNumber, currencyPair );
// Logujeme.
await log( 'Order SELL zrušen: ' + sellOrder.oderNumber + '\n' );
} // end ELSE
} // end IF
} // end ELSE IF
}) // end forEach() for BUY array
/* ####################### SELL LOOP ###################### */
// Pro každý order zařazený do seznamu pro SELL ordery (v minulém cyklu i teď).
ordersSell.forEach(async (sell, index) => {
// Zjišťumjeme aktuální stav orderu.
let orderState = await orderInfo( sell.orderNumber, currencyPair );
orderState = await orderState;
if (( orderState.status === 'closed' )) {
// Je-li order SELL v pořádku celý uzavřen, mažeme ho ze seznamu.
ordersSell.splice( index, 1 );
// Logujeme.
await log( 'Order SELL closed v pořádku: ' + sellOrder.oderNumber + '\n' );
// Jestliže není rozdíl mezi aktuální rate a highestBid zjištěnou na začátku cyklu 0.01 (cent)...
} else if (( orderState.status === 'open' )
&& (( orderState.rate - highestBid ) !== 0.01 )) {
// ... rušíme order (SELL).
await cancelOrder( sell.orderNumber, currencyPair );
// Současně odstraňujeme order (SELL) ze seznamu pro SELL ordery.
ordersSell.splice( index, 1 );
// Logujeme.
await log( 'Order SELL zrušen kvůli rate: ' + sellOrder.oderNumber + '\n' + (orderState.rate - highestBid) );
} // end ELSE IF
// Další akce už by neměly být třeba, protože buď se order (SELL) uzavřel
// a vše proběhlo úspěšně, nebo visí. Pokud je rozdíl mezi aktuální rate
// a highestBid zjištěnou na začátku 0.01, je vše v pořáku a order doběhne,
// v opačném případě je stornován.
}) // end forEach() for SELL array
} // end doBusiness()
/* ################################################################################################# *
* +++++++++++++++++++++++++++++++++++++++++ HELPERS +++++++++++++++++++++++++++++++++++++++++++++++ *
* ################################################################################################# */
// STOP TIMER
function stopTimer(timerID) {
clearInterval(timerID);
}
// CLEAN LOG
function cleanLog() {
// Clean the file only if the overall size exceedes cca 0.5MB.
fs.stat( logPath, function (err, stats) {
if (stats.size > 500000) {
fs.writeFile( logPath, '',
function errLog( err ) {
if ( err ) {
console.log( err );
log( err );
} // end IF
} // end FUNCT
) // end writeFile
} // end IF
}) // end FS.STAT
} // end cleanLog
// LOG
function log( message ) {
console.log( message );
fs.appendFile( logPath,
message, function errLog( err ) {
if ( err ) {
console.log( err );
log( err );
} // end IF
} // end FUNCT
) // end appendFile
}
// GET SIGN
async function getSign( form ) {
return await crypto.createHmac( 'sha512', SECRET ).update( form ).digest( 'hex' ).toString();
}
// PLACE ORDER
async function placeOrder ( currencyPair, rate, amount ) {
let form = { 'currencyPair': currencyPair, 'rate': rate, 'amount': amount };
let header = {};
header.KEY = KEY;
header.SIGN = await getSign(querystring.stringify(form));
let orderRes = await fetch(API_TRADE_URL + BUY_URL, { method: 'POST', headers: header, form: form } );
orderRes = orderRes.json();
return orderRes;
}
// ODER INFO
async function orderInfo ( orderNumber, currencyPair ) {
if (orderNumber !== undefined) {
let form = { 'currencyPair': currencyPair, 'orderNumber': orderNumber };
let header = { 'Content-Type': 'application/x-www-form-urlencoded' };
header.KEY = KEY;
header.SIGN = await getSign(querystring.stringify(form));
let orderRes = await fetch(API_TRADE_URL + GETORDER_URL, { headers: { 'User-Agent' : USER_AGENT } } );
orderRes = orderRes.json();
return orderRes;
} else {
console.log('Nemáme číslo orderu!');
}
}
// CANCEL ORDER
async function cancelOrder ( orderNumber, currencyPair ) {
let form = { 'currencyPair': currencyPair, 'orderNumber': orderNumber };
let header = { 'Content-Type': 'application/x-www-form-urlencoded' };
header.KEY = KEY;
header.SIGN = await getSign(querystring.stringify(form));
let orderRes = await fetch(API_TRADE_URL + CANCELORDER_URL, { method: 'POST', headers: header, form: form } );
orderRes = orderRes.json();
return orderRes;
}
// ORDER SELL
async function orderSell ( currencyPair, rate, amount ) {
let form = { 'currencyPair': currencyPair, 'rate': rate, 'amount': amount };
let header = {};
header.KEY = KEY;
header.SIGN = await getSign(querystring.stringify(form));
let orderRes = await fetch(API_TRADE_URL + SELL_URL, { method: 'POST', headers: header, form: form } );
orderRes = orderRes.json();
return orderRes;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment