Skip to content
This repository has been archived by the owner on Feb 15, 2022. It is now read-only.

Visual dashboard for REST API #850

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ data/*
conf.js
conf-*
conf_*
conf/*
!conf-sample.js
sim_result*
trade_result*
sim_result*.html
trade_result*.html
*_test
backtesting_*
models/*.json
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ neural
description:
Use neural learning to predict future price. Buy = mean(last 3 real prices) < mean(current & last prediction)
options:
--period=<value> period length - make sure to lower your poll trades time to lower than this value (default: 5s)
--period=<value> period length - make sure to lower your poll trades time to lower than this value (default: 2m)
--activation_1_type=<value> Neuron Activation Type: sigmoid, tanh, relu (default: sigmoid)
--neurons_1=<value> Neurons in layer 1 Shoot for atleast 100 (default: 5)
--depth=<value> Rows of data to predict ahead for matches/learning (default: 3)
Expand Down
62 changes: 43 additions & 19 deletions commands/trade.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ module.exports = function container (get, set, clear) {
process.exit(1)
}
var engine = get('lib.engine')(s)
get('lib.output').initializeOutput(s)

const keyMap = new Map()
keyMap.set('b', 'limit'.grey + ' BUY'.green)
Expand All @@ -96,7 +95,7 @@ module.exports = function container (get, set, clear) {
console.log(' ' + key + ' - ' + value)
})
}

function listOptions () {
console.log()
console.log(s.exchange.name.toUpperCase() + ' exchange active trading options:'.grey)
Expand Down Expand Up @@ -131,7 +130,7 @@ module.exports = function container (get, set, clear) {
z(20, so.profit_stop_pct + '%', ' ')
].join('') + '\n')
process.stdout.write('')
}
}

/* Implementing statistical Exit */
function printTrade (quit, dump) {
Expand All @@ -158,6 +157,14 @@ module.exports = function container (get, set, clear) {
output_lines.push('buy hold: ' + buy_hold.format('0.00000000').yellow + ' (' + n(buy_hold_profit).format('0.00%') + ')')
output_lines.push('vs. buy hold: ' + n(tmp_balance).subtract(buy_hold).divide(buy_hold).format('0.00%').yellow)
output_lines.push(s.my_trades.length + ' trades over ' + s.day_count + ' days (avg ' + n(s.my_trades.length / s.day_count).format('0.00') + ' trades/day)')
s.stats = {
profit: profit.format('0.00%'),
tmp_balance: n(tmp_balance).format('0.00000000'),
buy_hold: buy_hold.format('0.00000000'),
buy_hold_profit: n(buy_hold_profit).format('0.00%'),
day_count: s.day_count,
trade_per_day: n(s.my_trades.length / s.day_count).format('0.00')
}
var last_buy
var losses = 0, sells = 0
s.my_trades.forEach(function (trade) {
Expand All @@ -174,7 +181,11 @@ module.exports = function container (get, set, clear) {
if (s.my_trades.length && sells > 0) {
output_lines.push('win/loss: ' + (sells - losses) + '/' + losses)
output_lines.push('error rate: ' + (sells ? n(losses).divide(sells).format('0.00%') : '0.00%').yellow)
s.stats.win = (sells - losses)
s.stats.losses = losses
s.stats.error_rate = (sells ? n(losses).divide(sells).format('0.00%') : '0.00%')
}

output_lines.forEach(function (line) {
console.log(line)
})
Expand Down Expand Up @@ -202,56 +213,63 @@ module.exports = function container (get, set, clear) {
.replace(/\{\{symbol\}\}/g, so.selector + ' - zenbot ' + require('../package.json').version)
if (so.filename !== 'none') {
var out_target

if(dump){
var dt = new Date().toISOString();

//ymd
var today = dt.slice(2, 4) + dt.slice(5, 7) + dt.slice(8, 10);
out_target = so.filename || 'simulations/trade_result_' + so.selector +'_' + today + '_UTC.html'
fs.writeFileSync(out_target, out)
}else
out_target = so.filename || 'simulations/trade_result_' + so.selector +'_' + new Date().toISOString().replace(/T/, '_').replace(/\..+/, '').replace(/-/g, '').replace(/:/g, '').replace(/20/, '') + '_UTC.html'

fs.writeFileSync(out_target, out)
console.log('\nwrote'.grey, out_target)
}
if(quit) process.exit(0)
}
}
/* The end of printTrade */

/* Implementing statistical status dump every 10 secs */
var shouldSaveStats = false;
var shouldSaveStats = true;
function toggleStats(){
shouldSaveStats = !shouldSaveStats;
if(shouldSaveStats)
console.log("Auto stats dump enabled")
else
console.log("Auto stats dump disabled")
}

function saveStatsLoop(){
saveStats()
setTimeout(function () {
saveStatsLoop()
}, 10000)
}
saveStatsLoop()


function saveStats () {
if(!shouldSaveStats) return;

var output_lines = []
var tmp_balance = n(s.balance.currency).add(n(s.period.close).multiply(s.balance.asset)).format('0.00000000')

var profit = s.start_capital ? n(tmp_balance).subtract(s.start_capital).divide(s.start_capital) : n(0)
output_lines.push('last balance: ' + n(tmp_balance).format('0.00000000').yellow + ' (' + profit.format('0.00%') + ')')
var buy_hold = s.start_price ? n(s.period.close).multiply(n(s.start_capital).divide(s.start_price)) : n(tmp_balance)
var buy_hold_profit = s.start_capital ? n(buy_hold).subtract(s.start_capital).divide(s.start_capital) : n(0)
output_lines.push('buy hold: ' + buy_hold.format('0.00000000').yellow + ' (' + n(buy_hold_profit).format('0.00%') + ')')
output_lines.push('vs. buy hold: ' + n(tmp_balance).subtract(buy_hold).divide(buy_hold).format('0.00%').yellow)
output_lines.push(s.my_trades.length + ' trades over ' + s.day_count + ' days (avg ' + n(s.my_trades.length / s.day_count).format('0.00') + ' trades/day)')
s.stats = {
profit: profit.format('0.00%'),
tmp_balance: n(tmp_balance).format('0.00000000'),
buy_hold: buy_hold.format('0.00000000'),
buy_hold_profit: n(buy_hold_profit).format('0.00%'),
day_count: s.day_count,
trade_per_day: n(s.my_trades.length / s.day_count).format('0.00')
}
var last_buy
var losses = 0, sells = 0
s.my_trades.forEach(function (trade) {
Expand All @@ -268,8 +286,11 @@ module.exports = function container (get, set, clear) {
if (s.my_trades.length && sells > 0) {
output_lines.push('win/loss: ' + (sells - losses) + '/' + losses)
output_lines.push('error rate: ' + (sells ? n(losses).divide(sells).format('0.00%') : '0.00%').yellow)
s.stats.win = (sells - losses)
s.stats.losses = losses
s.stats.error_rate = (sells ? n(losses).divide(sells).format('0.00%') : '0.00%')
}

var html_output = output_lines.map(function (line) {
return colors.stripColors(line)
}).join('\n')
Expand All @@ -285,7 +306,7 @@ module.exports = function container (get, set, clear) {
})
var code = 'var data = ' + JSON.stringify(data) + ';\n'
code += 'var trades = ' + JSON.stringify(s.my_trades) + ';\n'
var tpl = fs.readFileSync(path.resolve(__dirname, '..', 'templates', 'sim_result.html.tpl'), {encoding: 'utf8'})
var tpl = fs.readFileSync(path.resolve(__dirname, '..', 'templates', 'trade_result.html.tpl'), {encoding: 'utf8'})
var out = tpl
.replace('{{code}}', code)
.replace('{{trend_ema_period}}', so.trend_ema || 36)
Expand All @@ -294,10 +315,10 @@ module.exports = function container (get, set, clear) {
if (so.filename !== 'none') {
var out_target
var dt = new Date().toISOString();

//ymd
var today = dt.slice(2, 4) + dt.slice(5, 7) + dt.slice(8, 10);
out_target = so.filename || 'simulations/trade_result_' + so.selector +'_' + today + '_UTC.html'
out_target = so.filename || 'stats/index.html'

fs.writeFileSync(out_target, out)
//console.log('\nwrote'.grey, out_target)
Expand Down Expand Up @@ -355,12 +376,15 @@ module.exports = function container (get, set, clear) {
opts.query.time = {$gt: db_cursor}
}
else {
trade_cursor = s.exchange.getCursor(query_start)
trade_cursor = s.exchange.getCursor(query_start)
opts.query.time = {$gte: query_start}
}
get('db.trades').select(opts, function (err, trades) {
if (err) throw err
if (!trades.length) {
console.log('------------------------------------------ INITIALIZE OUTPUT ------------------------------------------')
get('lib.output').initializeOutput(s)
saveStatsLoop()
console.log('---------------------------- STARTING ' + so.mode.toUpperCase() + ' TRADING ----------------------------')
if (so.mode === 'paper') {
console.log('!!! Paper mode enabled. No real trades are performed until you remove --paper from the startup command.')
Expand Down Expand Up @@ -439,7 +463,7 @@ module.exports = function container (get, set, clear) {
console.log('\nDumping statistics...'.grey)
printTrade(false, true)
} else if (key === 'D' && !info.ctrl) {

console.log('\nDumping statistics...'.grey)
toggleStats()
} else if (info.name === 'c' && info.ctrl) {
Expand Down
21 changes: 13 additions & 8 deletions extensions/exchanges/cexio/exchange.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
const CEX = require('cexio-api-node')
var path = require('path')
var n = require('numbro')
var minimist = require('minimist')

module.exports = function container (get, set, clear) {
var c = get('conf')
var s = {
options: minimist(process.argv)
}
var so = s.options

var public_client, authed_client

Expand Down Expand Up @@ -32,11 +37,11 @@ module.exports = function container (get, set, clear) {

function retry (method, args) {
if (method !== 'getTrades') {
console.error(('\nCEX.IO API is down! unable to call ' + method + ', retrying in 10s').red)
console.error(('\nCEX.IO API is down! unable to call ' + method + ', retrying in 15s').red)
}
setTimeout(function () {
exchange[method].apply(exchange, args)
}, 10000)
}, 15000)
}

var orders = {}
Expand All @@ -61,7 +66,7 @@ module.exports = function container (get, set, clear) {
var client = publicClient()
var pair = joinProduct(opts.product_id)
client.trade_history(pair, args, function (err, body) {
if (typeof body === 'string' && body.match(/error/)) console.log(('\ngetTrades ' + body).red)
if (so.debug && typeof body === 'string' && body.match(/error/)) console.log(('\ngetTrades ' + body).red)
if (err || (typeof body === 'string' && body.match(/error/))) return retry('getTrades', func_args, body)
var trades = body.map(function (trade) {
return {
Expand All @@ -80,7 +85,7 @@ module.exports = function container (get, set, clear) {
var func_args = [].slice.call(arguments)
var client = authedClient()
client.account_balance(function (err, body) {
if (typeof body === 'string' && body.match(/error/)) console.log(('\ngetBalance ' + body).red)
if (so.debug && typeof body === 'string' && body.match(/error/)) console.log(('\ngetBalance ' + body).red)
if (err || (typeof body === 'string' && body.match(/error/))) return retry('getBalance', func_args, body)
var balance = { asset: 0, currency: 0 }
balance.currency = n(body[opts.currency].available).add(body[opts.currency].orders).format('0.00000000')
Expand All @@ -96,7 +101,7 @@ module.exports = function container (get, set, clear) {
var client = publicClient()
var pair = joinProduct(opts.product_id)
client.ticker(pair, function (err, body) {
if (typeof body === 'string' && body.match(/error/)) console.log(('\ngetQuote ' + body).red)
if (so.debug && typeof body === 'string' && body.match(/error/)) console.log(('\ngetQuote ' + body).red)
if (err || (typeof body === 'string' && body.match(/error/))) return retry('getQuote', func_args, body)
cb(null, { bid: String(body.bid), ask: String(body.ask) })
})
Expand All @@ -107,7 +112,7 @@ module.exports = function container (get, set, clear) {
var client = authedClient()
client.cancel_order(opts.order_id, function (err, body) {
//if (body === 'Order canceled') return cb()
if (typeof body === 'string' && body.match(/error/)) console.log(('\ncancelOrder ' + body).red)
if (so.debug && typeof body === 'string' && body.match(/error/)) console.log(('\ncancelOrder ' + body).red)
if (err) return retry('cancelOrder', func_args, err)
cb()
})
Expand All @@ -126,7 +131,7 @@ module.exports = function container (get, set, clear) {
opts.type = 'market'
}
client.place_order(pair, action, opts.size, opts.price, opts.type, function (err, body) {
if (typeof body === 'string' && body.match(/error/)) console.log(('\ntrade ' + body).red)
if (so.debug && typeof body === 'string' && body.match(/error/)) console.log(('\ntrade ' + body).red)
if (err || (typeof body === 'string' && body.match(/error/) && body !== 'error: Error: Place order error: Insufficient funds.')) return retry('trade', func_args, body)
if (body === 'error: Error: Place order error: Insufficient funds.') {
var order = {
Expand Down Expand Up @@ -164,7 +169,7 @@ module.exports = function container (get, set, clear) {
var order = orders['~' + opts.order_id]
var client = authedClient()
client.get_order_details(opts.order_id, function (err, body) {
if (typeof body === 'string' && body.match(/error/)) console.log(('\ngetOrder ' + body).red)
if (so.debug && typeof body === 'string' && body.match(/error/)) console.log(('\ngetOrder ' + body).red)
if (err || (typeof body === 'string' && body.match(/error/))) return retry('getOrder', func_args, body)
if (body.status === 'c') {
order.status = 'rejected'
Expand Down
27 changes: 25 additions & 2 deletions extensions/output/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ module.exports = function container (get) {
let express = require('express')
let app = express()
let random_port = require('random-port')
let path = require("path")

let run = function(reporter, tradeObject) {
if (!reporter.port || reporter.port === 0) {
Expand All @@ -16,15 +17,37 @@ module.exports = function container (get) {
}
}

let objectWithoutKey = (object, key) => {
const {[key]: deletedKey, ...otherKeys} = object;
return otherKeys;
}

let startServer = function(port, tradeObject) {
tradeObject.port = port

app.set('views', path.join(__dirname+'../../../templates'));
app.set('view engine', 'ejs');

app.use('/assets', express.static(__dirname+'../../../templates/dashboard_assets'));
app.use('/assets-zenbot', express.static(__dirname+'../../../assets'));

app.get('/', function (req, res) {
let datas = objectWithoutKey(tradeObject, 'options')
datas = objectWithoutKey(tradeObject, 'lookback')
res.render('dashboard', datas);
})

app.get('/trades', function (req, res) {
res.send(tradeObject)
res.send(objectWithoutKey(tradeObject, 'options'))
})


app.get('/stats', function (req, res) {
res.sendFile(path.join(__dirname+'../../../stats/index.html'));
})

app.listen(port)
tradeObject.url = require('ip').address() + ':' + port + '/trades'
tradeObject.url = require('ip').address() + ':' + port + ''
console.log('api running on ' + tradeObject.url)
}

Expand Down
2 changes: 1 addition & 1 deletion extensions/strategies/neural/strategy.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ module.exports = function container (get, set, clear) {
name: 'neural',
description: 'Use neural learning to predict future price. Buy = mean(last 3 real prices) < mean(current & last prediction)',
getOptions: function () {
this.option('period', 'period length - make sure to lower your poll trades time to lower than this value', String, '1m')
this.option('period', 'period length - make sure to lower your poll trades time to lower than this value', String, '2m')
this.option('activation_1_type', "Neuron Activation Type: sigmoid, tanh, relu", String, 'sigmoid')
this.option('neurons_1', "Neurons in layer 1 Shoot for atleast 100", Number, 1)
this.option('depth', "Rows of data to predict ahead for matches/learning", Number, 5)
Expand Down
Loading