bitstamp_trading_gui
Version:
module which helps change existing orders on bitstamp to quickly adopt to price changes
700 lines (531 loc) • 25.5 kB
JavaScript
const version = "1.1.8"
console.log("bitstampServer", version)
const BitStampClient = require("./bitstampClient.js")
//server.js
const url = require('url')
var express = require('express');
var app = express();
var session = require('express-session')
var stream = require('stream');
fs = require('fs');
pairs = { xrp_btc: "xrp_btc", uni_btc: "uni_btc", ltc_btc: "ltc_btc", link_btc: "link_btc", xlm_btc: "xlm_btc", bch_btc: "bch_btc", aave_btc: "aave_btc", algo_btc: "algo_btc", comp_btc: "comp_btc", snx_btc: "snx_btc", bat_btc: "bat_btc", mkr_btc: "mkr_btc", zrx_btc: "zrx_btc", yfi_btc: "yfi_btc", uma_btc: "uma_btc", omg_btc: "omg_btc", knc_btc: "knc_btc", crv_btc: "crv_btc", audio_btc: "audio_btc", eth_btc: "eth_btc", btc_usd: "btc_usd", xrp_usd: "xrp_usd", uni_usd: "uni_usd", ltc_usd: "ltc_usd", link_usd: "link_usd", xlm_usd: "xlm_usd", bch_usd: "bch_usd", aave_usd: "aave_usd", algo_usd: "algo_usd", comp_usd: "comp_usd", snx_usd: "snx_usd", bat_usd: "bat_usd", mkr_usd: "mkr_usd", zrx_usd: "zrx_usd", yfi_usd: "yfi_usd", uma_usd: "uma_usd", omg_usd: "omg_usd", knc_usd: "knc_usd", crv_usd: "crv_usd", audio_usd: "audio_usd", grt_usd: "grt_usd", dai_usd: "dai_usd", gusd_usd: "gusd_usd", gbp_usd: "gbp_usd", eur_usd: "eur_usd", eth_usd: "eth_usd", usdt_usd: "usdt_usd", usdc_usd: "usdc_usd", pax_usd: "pax_usd", btc_gbp: "btc_gbp", xrp_gbp: "xrp_gbp", ltc_gbp: "ltc_gbp", link_gbp: "link_gbp", xlm_gbp: "xlm_gbp", bch_gbp: "bch_gbp", omg_gbp: "omg_gbp", eth_gbp: "eth_gbp", pax_gbp: "pax_gbp", btc_eur: "btc_eur", xrp_eur: "xrp_eur", uni_eur: "uni_eur", ltc_eur: "ltc_eur", link_eur: "link_eur", xlm_eur: "xlm_eur", bch_eur: "bch_eur", aave_eur: "aave_eur", algo_eur: "algo_eur", comp_eur: "comp_eur", snx_eur: "snx_eur", bat_eur: "bat_eur", mkr_eur: "mkr_eur", zrx_eur: "zrx_eur", yfi_eur: "yfi_eur", uma_eur: "uma_eur", omg_eur: "omg_eur", knc_eur: "knc_eur", crv_eur: "crv_eur", audio_eur: "audio_eur", grt_eur: "grt_eur", gbp_eur: "gbp_eur", eth_eur: "eth_eur", usdt_eur: "usdt_eur", usdc_eur: "usdc_eur", pax_eur: "pax_eur", link_eth: "link_eth", eth_2eth: "eth_2eth", btc_usdt: "btc_usdt", xrp_usdt: "xrp_usdt", eth_usdt: "eth_usdt", usdc_usdt: "usdc_usdt", btc_usdc: "btc_usdc", eth_usdc: "eth_usdc", btc_pax: "btc_pax", xrp_pax: "xrp_pax", eth_pax: "eth_pax", }
class BitstampGUIServer {
constructor(configuration) {
this.configuration = configuration
}
run() {
this.accounts = this.configuration.accounts
this.logInfo({ "accounts": this.accounts }, 3)
this.defaultAccountName = this.configuration.defaultAccount.name
this.logInfo({ "default account name": this.defaultAccountName }, 3)
var defaultAccountKey
for (var key in this.accounts) {
if (this.accounts[key].name == this.defaultAccountName) {
this.defaultAccountKey = key
}
}
this.logInfo({ "default account key": defaultAccountKey }, 3)
this.currentAccountKey = defaultAccountKey
const defaultAccount = this.configuration.defaultAccount
this.logInfo({ "default account": defaultAccount }, 3)
this.currentCurrency = defaultAccount.defaultCurrency.toLowerCase()
this.currentCrypto = defaultAccount.defaultCrypto.toLowerCase()
this.logInfo({ "current currency": this.currentCurrency }, 3)
this.logInfo({ "current crypto": this.currentCrypto }, 3)
this.client = new BitStampClient(this.configuration)
// const path = require('path')
process.once('SIGINT', function (code) {
console.log('SIGINT received, shutting down...');
process.exit()
});
app.use(session({
secret: 'chosen language',
saveUninitialized: true,
resave: false,
}))
// app.use(express.static('./html')); // set default directory
//setting the port.
var server = app.listen(3003, function (err) {
app.use(express.static(__dirname + '/'));
if (err) {
console.log(err.message)
}
// var host = app.address().address
// var port = app.address().port
console.log("***** Server listening at port 3003")
});
app.get('/', (request, response) => {
this.logInfo("***** reloading page", 1)
this.client.setAccount(defaultAccount)
this.currentCurrency = defaultAccount.defaultCurrency.toLowerCase()
this.currentCrypto = defaultAccount.defaultCrypto.toLowerCase()
this.currentAccountKey = defaultAccountKey
this.logInfo({ "current currency": this.currentCurrency }, 2)
this.logInfo({ "current crypto": this.currentCrypto }, 2)
response.sendFile(__dirname + '/html/bitstampGUI.html')
});
app.get('/cancelOrder', async (request, response) => {
try {
var t = request.url
var urlString = "http://www.some.crap" + t
var responseURL = new URL(urlString)
var params = new URLSearchParams(responseURL.search);
var id = params.get("id")
var fee = parseFloat(params.get("fee"))
var newPrice = parseFloat(params.get("newPrice"))
this.logInfo(`order ID to cancel\t${id}`, 1)
this.logInfo(`new Price\t${newPrice}`, 1)
this.logInfo(`fee\t${fee}`, 1)
let resultCancel = await this.client.doCancelOrder(id)
this.logInfo({ "result from cancel": resultCancel }, 2)
var resultCreate
if (resultCancel.type == 1) {
resultCreate = await this.client.createLimitSellOrder(resultCancel.amount, newPrice.toFixed(4))
} else {
var balances = await this.client.getAccountBalance()
amount = balances[this.currentCurrency]
crypto_original = balances[this.currentCrypto]
let currency_available = amount * (1 - fee) // deduct fee already
let newAmount = currency_available / newPrice
this.logInfo(`new amount\t${newAmount}`, 1)
resultCreate = await this.client.createLimitBuyOrder(newAmount.toFixed(4), newPrice.toFixed(4))
}
this.logInfo({ "result from new order": resultCreate }, 2)
response.json(resultCreate)
} catch (e) {
console.log(e)
}
});
app.get('/sellNow', async (request, response) => {
try {
var balances = await this.client.getAccountBalance()
var amount = balances[this.currentCrypto]
// check if orders available
var resultCreate
orders = await this.client.getOpenOrders()
if (orders.length > 0) {
order = orders[0]
this.logInfo({ "open order": order }, 2)
// type 0 = buy, type 1 = sell
if ("1" == order.type) {
this.logInfo("need to cancel existing sell order", 1)
// buy order which needs be cancelled
await this.client.doCancelOrder(order.id)
}
var balances = await this.client.getAccountBalance()
var amount = balances[this.currentCrypto]
//{ crypto: '0.00000000', currency: '0.00' }
if (0 < amount) {
resultCreate = await this.client.createInstantSellOrder(amount)
this.logInfo({ "instant sell result": resultCreate }, 1)
} else {
this.logInfo("nothing to sell available", 1)
}
} else {
this.logInfo("no open order to cancel", 1)
if (0 < amount) {
resultCreate = await this.client.createInstantSellOrder(amount)
this.logInfo({ "instant sell result": resultCreate }, 1)
} else {
this.logInfo("nothing to sell available", 1)
}
}
} catch (e) {
console.log(e)
}
});
app.get('/buyNow', async (request, response) => {
try {
var balances = await this.client.getAccountBalance()
var amount = balances[this.currentCurrency]
var resultCreate
// check if orders available
orders = await this.client.getOpenOrders()
if (orders.length > 0) {
order = orders[0]
this.logInfo("open order", 2)
this.logInfo(order, 2)
// type 0 = buy, type 1 = sell
if ("0" == order.type) {
this.logInfo("need to cancel existing buy order", 1)
// buy order which needs be cancelled
await this.client.doCancelOrder(order.id)
}
balances = await this.client.getAccountBalance()
amount = balances[this.currentCurrency]
if (0 < amount) {
resultCreate = await this.client.createInstantBuyOrder(amount)
this.logInfo({ "instant buy result": resultCreate }, 1)
} else {
this.logInfo("no money to buy available", 1)
}
} else {
this.logInfo("no open order to cancel", 1)
if (0 < amount) {
resultCreate = await this.client.createInstantBuyOrder(amount)
this.logInfo({ "instant buy result": resultCreate }, 1)
} else {
this.logInfo("no money to buy available", 1)
}
}
// now create instant buy order
} catch (e) {
console.log(e)
}
});
app.get('/getFee', async (request, response) => {
try {
var fee = await this.client.getFee()
this.logInfo({ "current fee": fee }, 1)
response.json(fee)
} catch (e) {
console.log(e)
}
});
app.get('/getCurrency', async (request, response) => {
try {
this.logInfo({ "current currency": this.currentCurrency }, 1)
response.json({ currency: this.currentCurrency.toUpperCase() })
} catch (e) {
console.log(e)
}
});
app.get('/setCurrency', async (request, response) => {
try {
var t = request.url
var urlString = "http://www.some.crap" + t
var responseURL = new URL(urlString)
var params = new URLSearchParams(responseURL.search);
this.currentCurrency = params.get("currency").toLowerCase()
this.logInfo({ "new currency": this.currentCurrency }, 1)
this.client.setCurrency(this.currentCurrency)
response.json({ result: "success" })
} catch (e) {
console.log(e)
}
});
app.get('/getAccounts', async (request, response) => {
try {
this.logInfo({ "accounts": this.accounts }, 1)
this.logInfo({ "defaultAccount": this.defaultAccountKey }, 1)
var accounts = this.accounts
response.json({ accounts, currentAccount: this.currentAccountKey })
} catch (e) {
console.log(e)
}
});
app.get('/changeAccount', async (request, response) => {
try {
var t = request.url
var urlString = "http://www.some.crap" + t
var responseURL = new URL(urlString)
var params = new URLSearchParams(responseURL.search);
var account = params.get("account")
this.logInfo({ "new account": account }, 1)
response.json({ result: "success" })
var newAccount = {}
// fetch new account
for (var key in this.accounts) {
if (key == account) {
newAccount = this.accounts[key]
this.currentAccountKey = key
}
}
this.logInfo({ "New account": newAccount }, 1)
this.client.setAccount(newAccount)
this.currentCurrency = newAccount.defaultCurrency.toLowerCase()
this.currentCrypto = newAccount.defaultCrypto.toLowerCase()
this.logInfo({ "current currency": this.currentCurrency }, 2)
this.logInfo({ "current crypto": this.currentCrypto }, 2)
} catch (e) {
console.log(e)
}
});
app.get('/getCrypto', async (request, response) => {
try {
this.logInfo({ "current crypto": this.currentCrypto }, 1)
response.json({ crypto: this.currentCrypto.toUpperCase() })
} catch (e) {
console.log(e)
}
});
app.get('/setCrypto', async (request, response) => {
try {
var t = request.url
var urlString = "http://www.some.crap" + t
var responseURL = new URL(urlString)
var params = new URLSearchParams(responseURL.search);
this.currentCrypto = params.get("crypto").toLowerCase()
console.log("new crypto")
console.log(this.currentCrypto)
this.client.setCrypto(this.currentCrypto)
response.json({ result: "success" })
} catch (e) {
console.log(e)
}
});
app.get('/writeBotThresholds', async (request, response) => {
try {
var t = request.url
var urlString = "http://www.some.crap" + t
var responseURL = new URL(urlString)
var params = new URLSearchParams(responseURL.search);
var high = params.get("high")
this.logInfo(`new high\t${high}`, 1)
var low = params.get("low")
this.logInfo(`new low\t${low}`, 1)
// here we write a file
fs.writeFile(this.configuration.path_bot_ini, 'high=' + high + "\rlow=" + low, function (err) {
if (err) {
console.log(err);
response.json({ result: "failure" })
}
this.logInfo("new thresholds written for bot to pick up", 1);
response.json({ result: "success" })
});
} catch (e) {
console.log(e)
}
});
app.get('/readBotThresholds', async (request, response) => {
try {
// here we write a file
const data = fs.readFileSync(this.configuration.path_bot_ini, 'utf8')
var params = data.split("\r")
this.logInfo({ "bot current high": params[0] }, 1)
this.logInfo({ "bot current low": params[1] }, 1)
var thresholds = { high: params[0].split("=")[1], low: params[1].split("=")[1] }
response.json(thresholds)
} catch (e) {
console.log(e)
response.json({ result: "failure" })
}
});
app.get('/getOpenOrder', async (request, response) => {
try {
// console.log(parts)
let result = await this.client.getOpenOrders()
if (result[0] === undefined) {
this.logInfo("no open orders to return", 1)
result = { "id": "", "buyPrice": "", type: "" }
response.json(result)
} else {
this.logInfo({ "open order": result[0] }, 1)
response.json(result[0])
}
} catch (e) {
console.log(e)
}
});
app.get('/getLastSellPrice', async (request, response) => {
try {
var lastSellPrice = await this.getLastSellPrice()
this.logInfo({ "last sell price": lastSellPrice }, 1)
response.json(lastSellPrice)
} catch (e) {
console.log(e)
}
});
app.get('/getCurrentPrice', async (request, response) => {
try {
var currentPrice = await this.getCurrentPrice()
this.logInfo({ "current price": currentPrice }, 1)
response.json(currentPrice)
} catch (e) {
console.log(e)
}
});
app.get('/getBalance', async (request, response) => {
try {
let result = await this.client.getAccountBalance(false)
this.logInfo({ "account Balance": result }, 2)
// console.log("currencCrypto", this.currentCrypto, "this.currentCurrency", this.currentCurrency)
// convert universal
var balances = {
crypto_available: result[this.currentCrypto + '_available'], crypto_reserved: result[this.currentCrypto + '_reserved'],
currency_available: result[this.currentCurrency + '_available'], currency_reserved: result[this.currentCurrency + '_reserved']
}
this.logInfo({ "returned to GUI": balances }, 2)
response.json(balances)
} catch (e) {
console.log(e)
}
});
app.get('/getTransactions', async (request, response) => {
try {
var t = request.url
var urlString = "http://www.some.crap" + t
var responseURL = new URL(urlString)
var params = new URLSearchParams(responseURL.search);
const dateFrom = new Date(params.get("dateFrom"))
this.logInfo({ "date from": dateFrom }, 1)
var txs = await this.getTransactions(dateFrom)
response.json(txs)
} catch (e) {
console.log(e)
}
});
//...
app.get('/download', async (request, response) => {
//...
var t = request.url
var urlString = "http://www.some.crap" + t
var responseURL = new URL(urlString)
var params = new URLSearchParams(responseURL.search);
const dateFrom = new Date(params.get("dateFrom"))
this.logInfo({ "date from": dateFrom }, 1)
var txs = await this.getTransactions(dateFrom)
var fileData = ""
// header
for (var k in txs[0]) {
if (k == "a1" || k == "a2") {
fileData += "Amount,"
} else if (k == "p1" || k == "p2") {
fileData += "Code,"
} else {
fileData += k + ","
}
}
fileData = fileData.substring(0, fileData.length - 1)
fileData += "\r"
for (var i in txs) {
for (var k in txs[i]) {
if (k == "datetime") {
fileData += '"' + txs[i][k].toISOString() + '",'
} else if ("p1" == k || "p2" == k) {
fileData += '"' + txs[i][k].toUpperCase() + '",'
}
else {
fileData += '"' + txs[i][k] + '",'
}
}
fileData = fileData.substring(0, fileData.length - 1)
fileData += "\r"
}
var fileContents = Buffer.from(fileData);
var readStream = new stream.PassThrough();
readStream.end(fileContents);
response.set('Content-disposition', 'attachment; filename=Transactions.csv');
response.set('Content-Type', 'text/plain');
readStream.pipe(response);
});
}
async getLowestPrice(orderID) {
var transactionFound = false
var transactions = await this.client.getUserTransactions("limit=60")
this.logInfo({ "last 10 transactions": transactions }, 3)
var minPrice = 999999999999
for (var transaction in transactions) {
//console.log(result[order])
//console.log(`Checking transactions: \t${transaction}`)
t = transactions[transaction].order_id
if (orderID == t) {
transactionFound = true
// console.log(`found sell transaction\t${order_id}`)
var price = transactions[transaction][`${this.currentCrypto}_${this.currentCurrency}`]
//console.log(`Price\t${price}`)
if (price < minPrice) {
minPrice = price
}
}
}
if (minPrice == 999999999999) {
minPrice = NaN
}
this.logInfo(`last minimum sell price\t${minPrice}`, 1)
return minPrice
}
async getLastSellPrice() {
var transactionFound = false
var transactions = await this.client.getUserTransactions("limit=40")
var lowestPrice = -1
var order_id = ""
for (var transaction in transactions) {
console.log(transactions[transaction])
var order_id = transactions[transaction].order_id
var xrp = parseFloat(transactions[transaction][`${this.currentCrypto}`])
var type = transactions[transaction].type
if (type == '2' && xrp < 0) {
transactionFound = true
// console.log(`found sell transaction\t${order_id}`)
lowestPrice = await this.getLowestPrice(order_id)
break
}
}
if (lowestPrice == -1) {
lowestPrice = NaN
}
return { "sellPrice": lowestPrice }
}
async getCurrentPrice() {
var ticker = await this.client.getHourlyTicker()
this.logInfo({ "current price, ticker": ticker }, 1)
return { "currentPrice": ticker.last }
}
async getTransactions(dateFrom) {
var result = await this.client.getUserTransactions("limit=1000")
// console.log(result)
var d = new Date()
const offset = d.getTimezoneOffset()
var price
var cryptoAmount
var currencyAmount
var order_id
var id
var type
var fee
var cryptoCode
var currencyCode
var pair
var dtString
var dt
var txs = []
for (var k in result) {
Object.keys(result[k]).forEach(function (key) {
var pos = key.indexOf("_")
if (0 < pos && "order_id" != key) {
// found pair
if (key in pairs) {
// confirmed pair
cryptoCode = key.substring(0, pos)
currencyCode = key.substring(pos + 1, key.length)
// console.log(currencyCode, cryptoCode)
pair = key
}
}
})
price = result[k][pair]
cryptoAmount = parseFloat(result[k][cryptoCode])
currencyAmount = parseFloat(result[k][currencyCode])
order_id = result[k]['order_id']
id = result[k]['id']
type = result[k]['type']
fee = result[k]['fee']
dtString = result[k]['datetime'].substring(0, 19)
var dtTemp = new Date(dtString)
dt = new Date(dtTemp - (2 * 60000 * offset)) // 2* cause the Date() caused recalculation of offset, now we have to "go back twice the offset
var tx = { order_id: order_id, id: id, datetime: dt, fee: fee, price: price, a1: cryptoAmount, p1: cryptoCode, a2: currencyAmount, p2: currencyCode, }
// console.log(tx)
if (dt >= dateFrom && type == "2") {
txs.push(tx)
}
}
return txs
}
async logInfo(info, level) {
// it not debugging, do not output to console
if (this.configuration.debug) {
if (level <= this.configuration.debugLevel) {
console.log(info)
}
}
// always output to file
if ('object' == typeof (info)) {
info = JSON.stringify(info)
}
// here we write a file
fs.appendFileSync(this.configuration.path_log, info);
fs.appendFileSync(this.configuration.path_log, "\r");
}
}
module.exports = BitstampGUIServer