I think this is the part that needs to integrated in zenbot
https://www.kraken.com/help/api#private-user-trading
Is this part implemented on zenbot 3.x for some other exchange?
not yet, but soon :)
If you are brave enough.. here is the kraken porting of default_logic.js which use gdax as data source. There are still many hardcoded stuff, but it quite works for now.
I still get errors like Error: Kraken API returned error: Order:Insufficient funds sometimes
var first_run = true
var last_balance_sig
var sync_start_balance = false
module.exports = function container (get, set, clear) {
var c = get('config')
var o = get('utils.object_get')
var n = require('numbro')
var tb = require('timebucket')
var sig = require('sig')
var format_currency = get('utils.format_currency')
var get_timestamp = get('utils.get_timestamp')
// var CoinbaseExchange = require('coinbase-exchange')
var KrakenClient = require('kraken-api');
// Put here your credentials
const kraken_key = ''
const kraken_secret = ''
var client
function onOrder (err, order) {
if (err) return get('logger').error('order err', err, order, {feed: 'errors'})
// if (resp.statusCode !== 200) {
// console.error(order)
// return get('logger').error('non-200 status: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: order}})
// }
get('logger').info('kraken', ('order-id: ' + order.txid[0]).cyan, {data: {order: order}})
function getStatus () {
client.api('QueryOrders', {"txid": order.txid[0] }, function(err, data) {
if (err) return get('logger').error('getOrder err', err)
const order_confirmation = data[order.txid[0]]
if (order.status === 'closed') {
return get('logger').info('kraken', ('order ' + order.txid[0] + ' closed ').cyan, {data: {order: order}})
}
else {
get('logger').info('kraken', ('order ' + order.txid[0] + ' ' + order.status).cyan, {data: {order: order}})
setTimeout(getStatus, 5000)
}
});
// client.getOrder(order.id, function (err, resp, order) {
// if (err) return get('logger').error('getOrder err', err)
// if (resp.statusCode !== 200) {
// console.error(order)
// return get('logger').error('non-200 status from getOrder: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: order}})
// }
// if (order.status === 'done') {
// return get('logger').info('kraken', ('order ' + order.id + ' done: ' + order.done_reason).cyan, {data: {order: order}})
// }
// else {
// get('logger').info('kraken', ('order ' + order.id + ' ' + order.status).cyan, {data: {order: order}})
// setTimeout(getStatus, 5000)
// }
// })
}
getStatus()
}
return [
// BEGIN DEFAULT TRADE LOGIC
// default params
function (tick, trigger, rs, cb) {
//get('logger').info('trader', 'KRAKEN strategy loaded')
rs.asset = 'BTC'
rs.currency = 'USD'
rs.rsi_period = '1h'
rs.rsi_up = 63
rs.rsi_down = 47
rs.check_period = '1m'
rs.exchange = 'gdax'
rs.selector = 'data.trades.' + rs.exchange + '.' + rs.asset + '-' + rs.currency
rs.hold_ticks = 100 // hold x check_period after trade
rs.trade_pct = 0.95 // trade % of current balance
rs.min_trade = 0.01
rs.start_balance = 1000
rs.min_roi_delta = -0.06 // accept a loss of up to 6%
cb()
},
// sync balance if key is present and we're in the `run` command
function (tick, trigger, rs, cb) {
if (get('command') !== 'run' || !c.gdax_key) {
return cb()
}
if (!client) {
// client = new CoinbaseExchange.AuthenticatedClient(c.gdax_key, c.gdax_secret, c.gdax_passphrase)
client = new KrakenClient(kraken_key, kraken_secret)
}
client.api('Balance', null, function(err, data) {
if (err) {
get('logger').info('kraken err', err)
}
// HACK non 200
if(!data) {
return cb()
}
// if (resp.statusCode !== 200) {
// console.error(data)
// get('logger').error('non-200 status from exchange: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: accounts}})
// return cb()
// }
rs.balance = {}
var accounts = data.result
var gdax_accounts = [
{currency:'BTC', balance:accounts['XXBT']},
{currency:'USD', balance:accounts['ZUSD']}
]
//get('logger').info('acc', JSON.stringify(gdax_accounts))
gdax_accounts.forEach(function (account) {
if (account.currency === rs.currency) {
rs.balance[rs.currency] = n(account.balance).value()
}
else if (account.currency === rs.asset) {
rs.balance[rs.asset] = n(account.balance).value()
}
})
if (first_run) {
sync_start_balance = true
}
var balance_sig = sig(rs.balance)
if (balance_sig !== last_balance_sig) {
get('logger').info('kraken', 'balance'.grey, n(rs.balance[rs.asset]).format('0.000').white, rs.asset.grey, n(rs.balance[rs.currency]).format('0.00').yellow, rs.currency.grey, {feed: 'exchange'})
last_balance_sig = balance_sig
}
cb()
})
// client.getAccounts(function (err, resp, accounts) {
// if (err) throw err
// if (resp.statusCode !== 200) {
// console.error(accounts)
// get('logger').error('non-200 status from exchange: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: accounts}})
// return cb()
// }
// rs.balance = {}
// accounts.forEach(function (account) {
// if (account.currency === rs.currency) {
// rs.balance[rs.currency] = n(account.balance).value()
// }
// else if (account.currency === rs.asset) {
// rs.balance[rs.asset] = n(account.balance).value()
// }
// })
// if (first_run) {
// sync_start_balance = true
// }
// var balance_sig = sig(rs.balance)
// if (balance_sig !== last_balance_sig) {
// get('logger').info(rs.exchange, 'balance'.grey, n(rs.balance[rs.asset]).format('0.000').white, rs.asset.grey, n(rs.balance[rs.currency]).format('0.00').yellow, rs.currency.grey, {feed: 'exchange'})
// last_balance_sig = balance_sig
// }
// cb()
// })
},
function (tick, trigger, rs, cb) {
// note the last close price
rs.market_price = o(tick, rs.selector + '.close')
rs.ticks || (rs.ticks = 0)
rs.progress || (rs.progress = 0)
if (!rs.market_price) return cb()
if (!rs.balance) {
// start with start_balance, neutral position
rs.balance = {}
rs.balance[rs.currency] = n(rs.start_balance).divide(2).value()
rs.balance[rs.asset] = n(rs.start_balance).divide(2).divide(rs.market_price).value()
}
rs.ticks++
if (tick.size !== rs.check_period) {
return cb()
}
// check price diff
rs.close = o(tick || {}, rs.selector + '.close')
// get rsi
rs.rsi_tick_id = tb(tick.time).resize(rs.rsi_period).toString()
get('ticks').load(get('app_name') + ':' + rs.rsi_tick_id, function (err, rsi_tick) {
if (err) return cb(err)
var rsi = o(rsi_tick || {}, rs.selector + '.rsi')
var trend
if (rsi) {
rs.rsi = rsi
}
// require minimum data
rs.close || (rs.close = o(rsi_tick || {}, rs.selector + '.close'))
if (!rs.rsi) {
get('logger').info('trader', ('no ' + rs.rsi_period + ' RSI for tick ' + rs.rsi_tick_id).red, {feed: 'trader'})
}
else if (rs.rsi.samples < c.rsi_periods) {
get('logger').info('trader', (rs.rsi_period + ' RSI: not enough samples for tick ' + rs.rsi_tick_id + ': ' + rs.rsi.samples).red, {feed: 'trader'})
}
else if (!rs.close) {
get('logger').info('trader', ('no close price for tick ' + rs.rsi_tick_id).red, {feed: 'trader'})
}
else {
if (rs.rsi.value >= rs.rsi_up) {
trend = 'UP'
}
else if (rs.rsi.value <= rs.rsi_down) {
trend = 'DOWN'
}
else {
trend = null
}
}
if (trend !== rs.trend) {
get('logger').info('trader', 'RSI:'.grey + rs.rsi.ansi, ('trend: ' + rs.trend + ' -> ' + trend).yellow, {feed: 'trader'})
delete rs.balance_warning
delete rs.roi_warning
}
rs.trend = trend
cb()
})
},
// @todo MACD
function (tick, trigger, rs, cb) {
cb()
},
// trigger trade signals
function (tick, trigger, rs, cb) {
if (rs.trend && rs.balance && rs.market_price) {
var size, new_balance = {}
// delay buying or selling, perhaps the trend intensifies
if (rs.hold_ticks_active) {
rs.hold_ticks_active--
}
if (rs.hold_ticks_active) {
rs.progress = n(1).subtract(n(rs.hold_ticks_active).divide(rs.hold_ticks)).value()
return cb()
}
rs.progress = 1
if (rs.trend === 'DOWN') {
// calculate sell size
size = rs.balance[rs.asset]
}
else if (rs.trend === 'UP') {
// calculate buy size
size = n(rs.balance[rs.currency]).divide(rs.market_price).value()
}
size = n(size || 0).multiply(rs.trade_pct).value()
// min size
if (!size || size < rs.min_trade) {
if (!rs.balance_warning) {
get('logger').info('trader', 'trend: '.grey, rs.trend, ('not enough balance, aborting trade!').red, {feed: 'trader'})
}
rs.balance_warning = true
return cb()
}
if (rs.trend === 'DOWN') {
// SELL!
new_balance[rs.currency] = n(rs.balance[rs.currency]).add(n(size).multiply(rs.market_price)).value()
new_balance[rs.asset] = n(rs.balance[rs.asset]).subtract(size).value()
rs.op = 'sell'
}
else if (rs.trend === 'UP') {
// BUY!
new_balance[rs.asset] = n(rs.balance[rs.asset]).add(size).value()
new_balance[rs.currency] = n(rs.balance[rs.currency]).subtract(n(size).multiply(rs.market_price)).value()
rs.op = 'buy'
}
else {
// unknown trend
get('logger').info('trader', ('unkown trend (' + rs.trend + ') aborting trade!').red, {feed: 'trader'})
return cb()
}
// consolidate balance
rs.new_end_balance = n(new_balance[rs.currency]).add(n(new_balance[rs.asset]).multiply(rs.market_price)).value()
if (sync_start_balance) {
rs.start_balance = rs.new_end_balance
sync_start_balance = false
}
rs.new_roi = n(rs.new_end_balance).divide(rs.start_balance).value()
rs.new_roi_delta = n(rs.new_roi).subtract(rs.roi || 0).value()
if (rs.roi && rs.new_roi_delta < rs.min_roi_delta) {
if (!rs.roi_warning) {
get('logger').info('trader', ('new ROI below delta threshold (' + n(rs.new_roi_delta).format('%0.000') + ' < ' + n(rs.min_roi_delta).format('%0.000') + ') aborting ' + rs.op + '!').red, {feed: 'trader'})
}
rs.roi_warning = true
return cb()
}
rs.hold_ticks_active = rs.hold_ticks + 1
rs.balance = new_balance
rs.end_balance = rs.new_end_balance
rs.roi = rs.new_roi
rs.trades || (rs.trades = 0)
rs.trades++
var trade = {
type: rs.op,
asset: rs.asset,
currency: rs.currency,
exchange: rs.exchange,
price: rs.market_price,
market: true,
size: size,
rsi: rs.rsi.value,
roi: rs.roi
}
trigger(trade)
if (get('command') === 'run' && c.gdax_key) {
// var params = {
// type: 'market',
// size: n(size).format('0.000000'),
// product_id: rs.asset + '-' + rs.currency
// }
// client[rs.op](params, function (err, resp, order) {
// onOrder(err, resp, order)
// })
const order = {
pair: 'XXBTZUSD',
type: rs.op,
ordertype: 'market', // market
//price: 0.01, //optional (in second currency)
volume: size //(first value)
}
client.api('AddOrder', order, function(err, data) {
if(err) {
console.log(err)
}
else {
console.log(data.result)
onOrder(err, data.result)
}
})
}
}
cb()
},
function (tick, trigger, rs, cb) {
first_run = false
cb()
}
// END DEFAULT TRADE LOGIC
]
}
Currently the code below works but I'm having weird errors:
08/19/2016 09:20:01 PM CEST [ reporter] 5m4905447 22 trades. 1h RSI 69x14 CLOSE: $575.21 USD trend:UP [link]
08/19/2016 09:20:01 PM CEST [ trader] trend: UP not enough balance, aborting trade! [link]
08/19/2016 09:20:01 PM CEST [kraken balance] balance XXX BTC XXX USD [link]
08/19/2016 09:19:42 PM CEST [ reducer] m24527239 5 trades. 08/19/2016 09:19:31 PM CEST BUY 4.097 at $575.33 BTC/USD [link]
08/19/2016 09:19:35 PM CEST [ gdax] m24527239 4 trades. 08/19/2016 09:19:31 PM CEST SELL 0.385 at $575.32 BTC/USD [link]
08/19/2016 09:19:03 PM CEST [ runner] starting [link]
08/19/2016 09:19:03 PM CEST [ launcher] cmd `run` booting [link]
08/19/2016 09:19:02 PM CEST [ launcher] cmd `run` exited with code 1, respawning now. [link]
08/19/2016 09:19:02 PM CEST [ kraken] order-id: XXX-XXX-XXX [link]
08/19/2016 09:19:01 PM CEST [ action] m24527238 buy {...}
08/19/2016 09:18:42 PM CEST [ reducer] m24527238
In particular the trade part i get [ trader] trend: UP not enough balance, aborting trade! but the order at market price and the balance is correctly updated.. @carlos8f ideas?
the run command crashed right after the buy action, which wasn't printed in the web console, but you should get a stack trace in the stderr log. The subsequent trend-up abort message is because the run_state for run command wasn't saved (due to the crash), and it forgot that it just traded, so it tried to trade again. If the run_state is persistent as it should be, there would be a hold period (controlled by hold_ticks setting) between trades.
Thanks, yes in the stderr the error was more explicit. I had an undefined where I check the order status.
Can I add kraken-api in the package.json? or you have another way to support the dependencies in the plugins?
ahh, cool. adding kraken-api is fine.
I am running this, but i got a lot [ kraken err] {} a lot.
I tried running it ./run.sh &>zenbot.log for stderr, but the output is same as in console.
How can i fix it and do i need to? Or maybe there is newer script for kraken.
@Sorrow2 yes it changed a bit, i'll share an updated version
Here is the code, you also have to use the kraken pairs convention in your configs ex.
c.default_selector = "kraken.XXBT-ZUSD"
var first_run = true
var last_balance_sig
var sync_start_balance = false
var assert = require('assert')
var n = require('numbro')
var tb = require('timebucket')
var sig = require('sig')
// var CoinbaseExchange = require('coinbase-exchange')
var KrakenClient = require('kraken-api');
// Put here your credentials
const kraken_key = ''
const kraken_secret = ''
module.exports = function container (get, set, clear) {
var c = get('config')
var o = get('utils.object_get')
var format_currency = get('utils.format_currency')
var get_timestamp = get('utils.get_timestamp')
var get_duration = get('utils.get_duration')
var get_tick_str = get('utils.get_tick_str')
var options = get('options')
var client
var start = new Date().getTime()
function onOrder (err, order) {
// if (err) return get('logger').error('order err', err, resp, order, {feed: 'errors'})
// if (resp.statusCode !== 200) {
// console.error(order)
// return get('logger').error('non-200 status: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: order}})
// }
// get('logger').info('gdax', c.default_selector.grey, ('order-id: ' + order.id).cyan, {data: {order: order}})
get('logger').info('kraken', ('order-id: ' + order.txid[0]).cyan, {data: {order: order}})
function getStatus () {
client.api('QueryOrders', {"txid": order.txid[0] }, function(err, data) {
// fix {} is ok
//if (err) return get('logger').error('getOrder err', err)
const order_confirmation = data.result[order.txid[0]]
if (order_confirmation.status === 'closed') {
return get('logger').info('kraken', ('order ' + order.txid[0] + ' closed ').cyan, {data: {order: order_confirmation}})
}
else {
get('logger').info('kraken', ('order ' + order.txid[0] + ' ' + order_confirmation.status).cyan, {data: {order: order_confirmation}})
setTimeout(getStatus, 5000)
}
})
// client.getOrder(order.id, function (err, resp, order) {
// if (err) return get('logger').error('getOrder err', err)
// if (resp.statusCode !== 200) {
// console.error(order)
// return get('logger').error('non-200 status from getOrder: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: order}})
// }
// if (order.status === 'done') {
// return get('logger').info('gdax', c.default_selector.grey, ('order ' + order.id + ' done: ' + order.done_reason).cyan, {data: {order: order}})
// }
// else {
// get('logger').info('gdax', c.default_selector.grey, ('order ' + order.id + ' ' + order.status).cyan, {data: {order: order}})
// setTimeout(getStatus, 5000)
// }
// })
}
getStatus()
}
return [
// BEGIN DEFAULT TRADE LOGIC
// default params
function (tick, trigger, rs, cb) {
rs.agent = USER_AGENT
var sMatch = c.default_selector.match(/^([^\.]+)\.([^-]+)-([^-]+)$/)
assert(sMatch)
rs.exchange = sMatch[1]
rs.asset = sMatch[2]
rs.currency = sMatch[3]
if (options.verbose && get('command') === 'run') {
get('logger').info('trader', c.default_selector.grey, get_tick_str(tick.id), 'running logic'.grey, rs.asset.grey, rs.currency.grey, {feed: 'trader'})
}
rs.rsi_period = '1h'
rs.rsi_up = 69 //70
rs.rsi_down = 29 //30
rs.check_period = '1m' //'5m'
rs.selector = 'data.trades.' + c.default_selector
rs.trade_pct = 0.98 // trade % of current balance
rs.fee_pct = 0.0026 // apply 0.25% taker fee
var products = get('exchanges.' + rs.exchange).products
products.forEach(function (product) {
if (product.asset === rs.asset && product.currency === rs.currency) {
rs.product = product
}
})
if (!rs.product) return cb(new Error('no product for ' + c.default_selector))
rs.min_trade = n(rs.product.min_size).multiply(1).value()
rs.sim_start_balance = 1000
rs.min_buy_wait = 86400000 * 1 // wait in ms after action before buying
rs.min_sell_wait = 86400000 * 1 // wait in ms after action before selling
rs.min_performance = -0.4 // abort trades with lower performance score
cb()
},
// sync balance if key is present and we're in the `run` command
function (tick, trigger, rs, cb) {
if (get('command') !== 'run' || !c.gdax_key) {
rs.start_balance = rs.sim_start_balance
// add timestamp for simulations
if (c.reporter_cols.indexOf('timestamp') === -1) {
c.reporter_cols.unshift('timestamp')
if (get('command') === 'run') {
get('logger').info('trader', c.default_selector.grey, ('No trader API key provided. Starting in advisor mode. --Zen').yellow, {feed: 'trader'})
}
}
if (get('command') === 'sim') {
// change reporting interval for sims
c.reporter_sizes = ['1h']
}
return cb()
}
if (!client) {
client = new KrakenClient(kraken_key, kraken_secret)
// client = new CoinbaseExchange.AuthenticatedClient(c.gdax_key, c.gdax_secret, c.gdax_passphrase)
}
client.api('Balance', null, function(err, data) {
// not {}
// if (err) {
// get('logger').info('kraken err bal', JSON.stringify(err))
// }
// HACK non 200
if(!data) {
return cb()
}
// if (resp.statusCode !== 200) {
// console.error(data)
// get('logger').error('non-200 status from exchange: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: accounts}})
// return cb()
// }
rs.balance = {}
var accounts = data.result
/*
var gdax_accounts = [
{currency:'XXBT', balance:accounts['XXBT']},
{currency:'ZUSD', balance:accounts['ZUSD']}
]
*/
var gdax_accounts = []
Object.keys(accounts).map( key => gdax_accounts.push({currency: key, balance:accounts[key]}) )
//get('logger').info('acc', JSON.stringify(gdax_accounts))
gdax_accounts.forEach(function (account) {
if (account.currency === rs.currency) {
rs.balance[rs.currency] = n(account.balance).value()
}
else if (account.currency === rs.asset) {
rs.balance[rs.asset] = n(account.balance).value()
}
})
if (first_run) {
sync_start_balance = true
}
var balance_sig = sig(rs.balance)
if (balance_sig !== last_balance_sig) {
get('logger').info('kraken balance', 'balance'.grey, n(rs.balance[rs.asset]).format('0.000').white, rs.asset.grey, n(rs.balance[rs.currency]).format('0.00').yellow, rs.currency.grey, {feed: 'exchange'})
last_balance_sig = balance_sig
}
cb()
})
// client.getAccounts(function (err, resp, accounts) {
// if (err) throw err
// if (resp.statusCode !== 200) {
// console.error(accounts)
// get('logger').error('non-200 status from exchange: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: accounts}})
// return cb()
// }
// rs.balance = {}
// accounts.forEach(function (account) {
// if (account.currency === rs.currency) {
// rs.balance[rs.currency] = n(account.balance).value()
// }
// else if (account.currency === rs.asset) {
// rs.balance[rs.asset] = n(account.balance).value()
// }
// })
// if (first_run) {
// sync_start_balance = true
// }
// var balance_sig = sig(rs.balance)
// if (balance_sig !== last_balance_sig) {
// get('logger').info('trader', c.default_selector.grey, '"Starting REAL trading! Hold on to your butts!" --Zen'.cyan, ' Balance:'.grey, n(rs.balance[rs.asset]).format('0.000').white, rs.asset.grey, n(rs.balance[rs.currency]).format('0.00').yellow, rs.currency.grey, {feed: 'exchange'})
// last_balance_sig = balance_sig
// }
// cb()
// })
},
function (tick, trigger, rs, cb) {
if (tick.size !== rs.check_period) {
return cb()
}
// note the last close price
var market_price = o(tick, rs.selector + '.close')
// sometimes the tick won't have a close price for this selector.
// keep old close price in memory.
if (market_price) {
rs.market_price = market_price
}
rs.ticks || (rs.ticks = 0)
rs.progress || (rs.progress = 0)
if (!rs.market_price) {
//get('logger').info('trader', ('no close price for tick ' + tick.id).red, {feed: 'trader'})
return cb()
}
if (!rs.balance) {
// start with start_balance, neutral position
rs.balance = {}
rs.balance[rs.currency] = n(rs.start_balance).divide(2).value()
rs.balance[rs.asset] = n(rs.start_balance).divide(2).divide(rs.market_price).value()
}
rs.consolidated_balance = n(rs.balance[rs.currency]).add(n(rs.balance[rs.asset]).multiply(rs.market_price)).value()
if (sync_start_balance) {
rs.start_balance = rs.consolidated_balance
sync_start_balance = false
}
rs.roi = n(rs.consolidated_balance).divide(rs.start_balance).value()
rs.ticks++
// get rsi
rs.rsi_tick_id = tb(tick.time).resize(rs.rsi_period).toString()
get('ticks').load(get('app_name') + ':' + rs.rsi_tick_id, function (err, rsi_tick) {
if (err) return cb(err)
var rsi = o(rsi_tick || {}, rs.selector + '.rsi')
var trend
if (rsi) {
rs.rsi = rsi
}
// require minimum data
if (!rs.rsi) {
if (!rs.rsi_warning) {
get('logger').info('trader', c.default_selector.grey, ('no ' + rs.rsi_period + ' RSI for tick ' + rs.rsi_tick_id).red, {feed: 'trader'})
}
rs.rsi_warning = true
}
else if (rs.rsi.samples < c.rsi_periods) {
if (!rs.rsi_warning) {
get('logger').info('trader', c.default_selector.grey, (rs.rsi_period + ' RSI: not enough samples for tick ' + rs.rsi_tick_id + ': ' + rs.rsi.samples).red, {feed: 'trader'})
}
rs.rsi_warning = true
}
else {
if (rs.rsi.value >= rs.rsi_up) {
trend = 'UP'
}
else if (rs.rsi.value <= rs.rsi_down) {
trend = 'DOWN'
}
else {
trend = null
}
}
if (trend !== rs.trend) {
get('logger').info('trader', c.default_selector.grey, 'RSI:'.grey + rs.rsi.ansi, ('trend: ' + rs.trend + ' -> ' + trend).yellow, {feed: 'trader'})
delete rs.balance_warning
delete rs.roi_warning
delete rs.rsi_warning
delete rs.delta_warning
delete rs.buy_warning
delete rs.perf_warning
delete rs.action_warning
delete rs.trend_warning
}
rs.trend = trend
cb()
})
},
// @todo MACD
function (tick, trigger, rs, cb) {
cb()
},
// trigger trade signals
function (tick, trigger, rs, cb) {
if (tick.size !== rs.check_period) {
return cb()
}
// for run command, don't trade unless this is a new tick
if (get('command') !== 'sim' && tick.time < start) {
get('logger').info('trader', c.default_selector.grey, ('skipping historical tick ' + tick.id).grey, {feed: 'trader'})
return cb()
}
if (rs.trend && !rs.trend_warning) {
get('logger').info('trader', c.default_selector.grey, ('acting on trend: ' + rs.trend + '!').yellow, {feed: 'trader'})
if (!rs.balance) {
get('logger').info('trader', c.default_selector.grey, ('no balance to act on trend: ' + rs.trend + '!').red, {feed: 'trader'})
}
if (!rs.market_price) {
get('logger').info('trader', c.default_selector.grey, ('no market_price to act on trend: ' + rs.trend + '!').red, {feed: 'trader'})
}
rs.trend_warning = true
}
rs.progress = 1
if (rs.trend && rs.balance && rs.market_price) {
var size, new_balance = {}
if (rs.trend === 'DOWN') {
// calculate sell size
size = rs.balance[rs.asset]
}
else if (rs.trend === 'UP') {
// calculate buy size
size = n(rs.balance[rs.currency]).divide(rs.market_price).value()
}
size = n(size || 0).multiply(rs.trade_pct).value()
if (rs.trend === 'DOWN') {
// SELL!
if (rs.last_action_time && tick.time - rs.last_action_time <= rs.min_sell_wait) {
if (!rs.sell_warning) {
get('logger').info('trader', c.default_selector.grey, ('too soon to sell after ' + rs.last_op + '! waiting ' + get_duration(n(rs.min_sell_wait).subtract(n(tick.time).subtract(rs.last_action_time)).multiply(1000).value())).red, {feed: 'trader'})
}
rs.sell_warning = true
return cb()
}
new_balance[rs.currency] = n(rs.balance[rs.currency]).add(n(size).multiply(rs.market_price)).value()
new_balance[rs.asset] = n(rs.balance[rs.asset]).subtract(size).value()
rs.op = 'sell'
if (!rs.action_warning) {
get('logger').info('trader', c.default_selector.grey, ('attempting to sell ' + n(size).format('0.00000000') + ' ' + rs.asset + ' for ' + format_currency(n(size).multiply(rs.market_price).value(), rs.currency) + ' ' + rs.currency).yellow, {feed: 'trader'})
}
rs.action_warning = true
}
else if (rs.trend === 'UP') {
// BUY!
if (rs.last_action_time && tick.time - rs.last_action_time <= rs.min_buy_wait) {
if (!rs.buy_warning) {
get('logger').info('trader', c.default_selector.grey, ('too soon to buy after ' + rs.last_op + '! waiting ' + get_duration(n(rs.min_buy_wait).subtract(n(tick.time).subtract(rs.last_action_time)).multiply(1000).value())).red, {feed: 'trader'})
}
rs.buy_warning = true
return cb()
}
new_balance[rs.asset] = n(rs.balance[rs.asset]).add(size).value()
new_balance[rs.currency] = n(rs.balance[rs.currency]).subtract(n(size).multiply(rs.market_price)).value()
rs.op = 'buy'
if (!rs.action_warning) {
get('logger').info('trader', c.default_selector.grey, ('attempting to buy ' + n(size).format('0.00000000') + ' ' + rs.asset + ' for ' + format_currency(n(size).multiply(rs.market_price).value(), rs.currency) + ' ' + rs.currency).yellow, {feed: 'trader'})
}
rs.action_warning = true
}
else {
// unknown trend
get('logger').info('trader', c.default_selector.grey, ('unkown trend (' + rs.trend + ') aborting trade!').red, {feed: 'trader'})
return cb()
}
// min size
if (!size || size < rs.min_trade) {
if (!rs.balance_warning) {
get('logger').info('trader', c.default_selector.grey, 'trend: '.grey, rs.trend, ('not enough funds (' + (rs.op === 'sell' ? n(size).format('0.00000000') : format_currency(rs.balance[rs.currency], rs.currency)) + ' ' + (rs.op === 'sell' ? rs.asset : rs.currency) + ') to execute min. ' + rs.op + ' ' + rs.min_trade + ', aborting trade!').red, {feed: 'trader'})
}
rs.balance_warning = true
return cb()
}
// fee calc
rs.fee = n(size).multiply(rs.market_price).multiply(rs.fee_pct).value()
new_balance[rs.currency] = n(new_balance[rs.currency]).subtract(rs.fee).value()
// consolidate balance
rs.new_end_balance = n(new_balance[rs.currency]).add(n(new_balance[rs.asset]).multiply(rs.market_price)).value()
rs.new_roi = n(rs.new_end_balance).divide(rs.start_balance).value()
rs.new_roi_delta = n(rs.new_roi).subtract(rs.roi || 0).value()
if (rs.op === 'buy') {
// % drop
rs.performance = rs.last_sell_price ? n(rs.last_sell_price).subtract(rs.market_price).divide(rs.last_sell_price).value() : null
rs.waited = rs.last_action_time ? get_duration(n(tick.time).subtract(rs.last_action_time).multiply(1000).value()) : null
}
else {
// % gain
rs.performance = rs.last_buy_price ? n(rs.market_price).subtract(rs.last_buy_price).divide(rs.last_buy_price).value() : null
rs.waited = rs.last_action_time ? get_duration(n(tick.time).subtract(rs.last_action_time).multiply(1000).value()) : null
}
if (rs.min_performance && rs.performance !== null && rs.performance < rs.min_performance) {
if (!rs.perf_warning) {
get('logger').info('trader', c.default_selector.grey, ('aborting ' + rs.op + ' due to low perf. = ' + n(rs.performance).format('0.000')).red, {feed: 'trader'})
}
rs.perf_warning = true
return cb()
}
rs.balance = new_balance
rs.end_balance = rs.new_end_balance
rs.roi = rs.new_roi
rs.num_trades || (rs.num_trades = 0)
rs.num_trades++
var trade = {
type: rs.op,
asset: rs.asset,
currency: rs.currency,
exchange: rs.exchange,
price: rs.market_price,
fee: rs.fee,
market: true,
size: size,
rsi: rs.rsi.value,
roi: rs.roi,
roi_delta: rs.new_roi_delta,
performance: rs.performance,
waited: rs.waited,
balance: new_balance,
end_balance: rs.new_end_balance
}
trigger(trade)
if (client) {
const order = {
// pair: 'XXBTZUSD',
pair: rs.asset+''+rs.currency,
type: rs.op,
ordertype: 'market', // market
//price: 0.01, //optional (in second currency)
volume: size //(first value)
}
client.api('AddOrder', order, function(err, data) {
if(err) {
console.log(err)
}
else {
console.log(data.result)
onOrder(err, data.result)
}
})
// var params = {
// type: 'market',
// size: n(size).format('0.000000'),
// product_id: rs.asset + '-' + rs.currency
// }
// client[rs.op](params, function (err, resp, order) {
// onOrder(err, resp, order)
// })
}
else if (!rs.sim_warning) {
get('logger').info('trader', c.default_selector.grey, ('Relax! This is a simulated trade! No real transaction will take place. --Zen').yellow, {feed: 'trader'})
rs.sim_warning = true
}
if (rs.op === 'buy') {
rs.last_buy_price = rs.market_price
}
else {
rs.last_sell_price = rs.market_price
}
rs.last_action_time = tick.time
rs.last_op = rs.op
}
cb()
},
function (tick, trigger, rs, cb) {
first_run = false
cb()
}
// END DEFAULT TRADE LOGIC
]
}
Thanks.
I don't get kraken err {} now, but i see no RSI change now (longer logs are the same). I am running with 3.5.14 build.
I have kraken and gdax in c.watch_exchanges. If i leave just kraken - no output in console.
Did i miss something?
08/26/2016 06:04:07 PM MSK [ reporter] m24537063 13 trades. --- RSI: 38 CLOSE: 576.990 ZUSD kraken.XXBT-ZUSD BAL: 581.269 ROI:1.000
08/26/2016 06:04:19 PM MSK [ gdax] m24537064 3 trades. 08/26/2016 06:04:05 PM MSK BUY 3.407 at $578.42 BTC/USD
08/26/2016 06:05:04 PM MSK [ gdax] m24537065 2 trades. 08/26/2016 06:05:01 PM MSK BUY 0.826 at $578.41 BTC/USD
08/26/2016 06:05:06 PM MSK [ reporter] m24537064 1 trades. --- RSI: 38 CLOSE: 576.990 ZUSD kraken.XXBT-ZUSD BAL: 581.269 ROI:1.000
08/26/2016 06:06:04 PM MSK [ reporter] m24537065 1 trades. --- RSI: 38 CLOSE: 576.990 ZUSD kraken.XXBT-ZUSD BAL: 581.269 ROI:1.000
08/26/2016 06:07:09 PM MSK [ reporter] m24537066 1 trades. --- RSI: 38 CLOSE: 576.990 ZUSD kraken.XXBT-ZUSD BAL: 581.269 ROI:1.000
08/26/2016 06:08:05 PM MSK [ gdax] m24537068 2 trades. 08/26/2016 06:08:00 PM MSK BUY 0.965 at $578.41 BTC/USD
08/26/2016 06:08:08 PM MSK [ reporter] m24537067 1 trades. --- RSI: 38 CLOSE: 576.990 ZUSD kraken.XXBT-ZUSD BAL: 581.269 ROI:1.000
Are you sure you are running the newer version because you shouldn't see [ gdax] anymore
Yes. I run second version of script you posted here. I saved it as kraken_logic.js.
I see gdax only if i have it in c.watch_exchanges.
If i have only kraken, nothing happens
08/26/2016 07:53:45 PM MSK [ launcher] cmd `server` booting
08/26/2016 07:53:45 PM MSK [ server] zenbot/3.5.14 booted!
08/26/2016 07:53:45 PM MSK [ server] open http://localhost:3013/?secret=d14a02121fd65e to see a live graph.
No output after this.
Here is the rest of my config
// watch these exchanges
c.watch_exchanges = [
//"bitfinex",
// "gdax",
"kraken",
//"poloniex"
]
// selector for indicators, trading, etc
c.default_selector = "kraken.XXBT-ZUSD"
// add selectors in the format "{exchange-slug}.{asset}-{currency}" to graph them
c.graph_selectors = [
c.default_selector,
"gdax.ETH-BTC",
"gdax.ETH-USD"
]
// trade logic
c.logic = require('./kraken_logic')
and i put c.default_selector = "kraken.XXBT-ZUSD" in config_btc_usd.js
I don't know, I replaced kraken.XXBT-ZUSD everywhere and it works. Try with --verbose
08/26/2016 08:04:01 PM CEST [ trader] kraken.XXBT-ZUSD m24537243 running logic XXBT ZUSD [link]
08/26/2016 08:04:01 PM CEST [ runner] m24537243 running [link]
08/26/2016 08:03:47 PM CEST [ kraken] m24537243 5 trades. 08/26/2016 08:03:32 PM CEST SELL 0.601 at 578.946 XXBT/ZUSD [link]
08/26/2016 08:03:39 PM CEST [ kraken] m24537243 3 trades. 08/26/2016 08:03:32 PM CEST SELL 0.405 at 578.943 XXBT/ZUSD [link]
08/26/2016 08:03:28 PM CEST [ kraken] m24537243 5 trades. 08/26/2016 08:03:28 PM CEST SELL 0.517 at 578.950 XXBT/ZUSD [link]
08/26/2016 08:03:26 PM CEST [ kraken] m24537243 2 trades. 08/26/2016 08:03:25 PM CEST SELL 0.217 at 578.950 XXBT/ZUSD [link]
08/26/2016 08:03:06 PM CEST [ runner] waiting for next 1m tick... [link]
are you using 3.5.14?
it seems that it doesn't connect to kraken here. If i use default config and i add kraken in c.watch_exchanges, i see no kraken output.
But it works for poloniex, gdax and bitfinex.
Any idea?
I have made a fresh install of latest (3.5.16) version to VPS, and i see same issue there:
no kraken output,
but poloniex, gdax, bitfinex - fine
I don't know what to say.. usually when I get no output is because I've wrong currencies pairs.. in kraken there are no BTC or USD, you have to use XETH XXBT ZUSD ZEUR .. in every config
i don't even add pairs.
I did fresh install. cp config_samle.js config.js
And uncomment exchanges:
// watch these exchanges
c.watch_exchanges = [
"bitfinex",
"gdax",
"kraken",
"poloniex"
]
And it works for other exchanges
08/30/2016 11:06:50 AM MSK [ server] zenbot/3.5.16 booted!
08/30/2016 11:06:50 AM MSK [ server] open http://localhost:3013/?secret=9ba935d84df1c2cc to see a live graph.
08/30/2016 11:06:50 AM MSK [ poloniex] m24542406 17 trades. 08/30/2016 11:06:13 AM MSK BUY 0.131 at 580.448 BTC/USDT
08/30/2016 11:06:50 AM MSK [ bitfinex] m24542405 10 trades. 08/30/2016 11:05:52 AM MSK SELL 4.114 at $580.00 BTC/USD
08/30/2016 11:06:50 AM MSK [ gdax] m24542406 39 trades. 08/30/2016 11:06:46 AM MSK SELL 6.451 at $575.68 BTC/USD
08/30/2016 11:07:00 AM MSK [ runner] m24542406 running
08/30/2016 11:07:00 AM MSK [ trader] gdax.BTC-USD m24542406 running logic BTC USD
Hello,
Same issue that Sorrow2.
fresh install, i use your "kraken_logic.js", and no output from kraken.
I used the --verbose but nothing to see.
Are your sure that c.default_selector = "kraken.XXBT-ZUSD" ?
in plugins/kraken/exchange.json it's "XXBTZUD" so it could be: c.default_selector = "kraken.XXBTZUSD"
i tried it too, but nothing to see.....
this is the config.js i use:
var c = module.exports = require('./config_defaults')()
// mongo stuff
c.mongo_url = "mongodb://localhost:27017/zenbrain-multi-kraken" // change if your mongo server isn't local
c.mongo_username = null // normally not needed
c.mongo_password = null
c.gdax_key = '' // TO ENABLE BOT TRADING: set this to GDAX api key,
c.gdax_secret = '' // set this to GDAX api secret,
c.gdax_passphrase = '' // set this to GDAX api passphrase.
c.trade_log = true // log new trades as they come in.
// watch these exchanges
c.watch_exchanges = [
//"bitfinex",
// "gdax",
"kraken",
//"poloniex"
]
// selector for indicators, trading, etc
c.default_selector = "kraken.XXBT-ZUSD"
// add selectors in the format "{exchange-slug}.{asset}-{currency}" to graph them
c.graph_selectors = [
c.default_selector,
"kraken.XETH-XXBT",
"kraken.XETH-ZUSD"
]
// trade logic
c.logic = require('./default_logic')
ok, and your "default_logic" ?
default_logic.js
var first_run = true
var last_balance_sig
var sync_start_balance = false
var assert = require('assert')
var n = require('numbro')
var tb = require('timebucket')
var sig = require('sig')
// var CoinbaseExchange = require('coinbase-exchange')
var KrakenClient = require('kraken-api');
// Put here your credentials
const kraken_key = ''
const kraken_secret = ''
module.exports = function container (get, set, clear) {
var c = get('config')
var o = get('utils.object_get')
var format_currency = get('utils.format_currency')
var get_timestamp = get('utils.get_timestamp')
var get_duration = get('utils.get_duration')
var get_tick_str = get('utils.get_tick_str')
var options = get('options')
var client
var start = new Date().getTime()
function onOrder (err, order) {
// if (err) return get('logger').error('order err', err, resp, order, {feed: 'errors'})
// if (resp.statusCode !== 200) {
// console.error(order)
// return get('logger').error('non-200 status: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: order}})
// }
// get('logger').info('gdax', c.default_selector.grey, ('order-id: ' + order.id).cyan, {data: {order: order}})
get('logger').info('kraken', ('order-id: ' + order.txid[0]).cyan, {data: {order: order}})
function getStatus () {
client.api('QueryOrders', {"txid": order.txid[0] }, function(err, data) {
// fix {} is ok
//if (err) return get('logger').error('getOrder err', err)
const order_confirmation = data.result[order.txid[0]]
if (order_confirmation.status === 'closed') {
return get('logger').info('kraken', ('order ' + order.txid[0] + ' closed ').cyan, {data: {order: order_confirmation}})
}
else {
get('logger').info('kraken', ('order ' + order.txid[0] + ' ' + order_confirmation.status).cyan, {data: {order: order_confirmation}})
setTimeout(getStatus, 5000)
}
})
// client.getOrder(order.id, function (err, resp, order) {
// if (err) return get('logger').error('getOrder err', err)
// if (resp.statusCode !== 200) {
// console.error(order)
// return get('logger').error('non-200 status from getOrder: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: order}})
// }
// if (order.status === 'done') {
// return get('logger').info('gdax', c.default_selector.grey, ('order ' + order.id + ' done: ' + order.done_reason).cyan, {data: {order: order}})
// }
// else {
// get('logger').info('gdax', c.default_selector.grey, ('order ' + order.id + ' ' + order.status).cyan, {data: {order: order}})
// setTimeout(getStatus, 5000)
// }
// })
}
getStatus()
}
return [
// BEGIN DEFAULT TRADE LOGIC
// default params
function (tick, trigger, rs, cb) {
rs.agent = USER_AGENT
var sMatch = c.default_selector.match(/^([^\.]+)\.([^-]+)-([^-]+)$/)
assert(sMatch)
rs.exchange = sMatch[1]
rs.asset = sMatch[2]
rs.currency = sMatch[3]
if (options.verbose && get('command') === 'run') {
get('logger').info('trader', c.default_selector.grey, get_tick_str(tick.id), 'running logic'.grey, rs.asset.grey, rs.currency.grey, {feed: 'trader'})
}
rs.rsi_query_limit = 100 // RSI initial value lookback
rs.rsi_periods = 26 // RSI smoothing factor
rs.rsi_period = '5m' // RSI tick size
rs.rsi_up = 65 // upper RSI threshold
rs.rsi_down = 28 // lower RSI threshold
rs.check_period = '1m' // speed to trigger actions at
rs.selector = 'data.trades.' + c.default_selector
rs.trade_pct = 0.98 // trade % of current balance
rs.fee_pct = 0.0026 // apply 0.25% taker fee
var products = get('exchanges.' + rs.exchange).products
products.forEach(function (product) {
if (product.asset === rs.asset && product.currency === rs.currency) {
rs.product = product
}
})
if (!rs.product) return cb(new Error('no product for ' + c.default_selector))
rs.min_trade = n(rs.product.min_size).multiply(1).value()
rs.sim_start_balance = 10000
rs.min_double_wait = 86400000 * 1 // wait in ms after action before doing same action
rs.min_reversal_wait = 86400000 * 0.75 // wait in ms after action before doing opposite action
rs.min_performance = -0.015 // abort trades with lower performance score
if (first_run) {
delete rs.real_trade_warning
}
cb()
},
// sync balance if key is present and we're in the `run` command
function (tick, trigger, rs, cb) {
if (get('command') !== 'run' || !c.gdax_key) {
rs.start_balance = rs.sim_start_balance
// add timestamp for simulations
if (c.reporter_cols.indexOf('timestamp') === -1) {
c.reporter_cols.unshift('timestamp')
if (get('command') === 'run') {
get('logger').info('trader', c.default_selector.grey, ('No trader API key provided. Starting in advisor mode. --Zen').yellow, {feed: 'trader'})
}
}
if (get('command') === 'sim') {
// change reporting interval for sims
c.reporter_sizes = ['1h']
}
return cb()
}
if (!client) {
client = new KrakenClient(kraken_key, kraken_secret)
// client = new CoinbaseExchange.AuthenticatedClient(c.gdax_key, c.gdax_secret, c.gdax_passphrase)
}
client.api('Balance', null, function(err, data) {
// not {}
// if (err) {
// get('logger').info('kraken err bal', JSON.stringify(err))
// }
// HACK non 200
if(!data) {
return cb()
}
// if (resp.statusCode !== 200) {
// console.error(data)
// get('logger').error('non-200 status from exchange: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: accounts}})
// return cb()
// }
rs.balance = {}
var accounts = data.result
// var gdax_accounts = [
// {currency:'ZEUR', balance:accounts['ZEUR']},
// {currency:'XXBT', balance:accounts['XXBT']},
// {currency:'ZUSD', balance:accounts['ZUSD']}
// ]
var gdax_accounts = []
Object.keys(accounts).map( key => gdax_accounts.push({currency: key, balance:accounts[key]}) )
//get('logger').info('acc', JSON.stringify(gdax_accounts))
gdax_accounts.forEach(function (account) {
if (account.currency === rs.currency) {
rs.balance[rs.currency] = n(account.balance).value()
}
else if (account.currency === rs.asset) {
rs.balance[rs.asset] = n(account.balance).value()
}
})
if (first_run) {
sync_start_balance = true
}
var balance_sig = sig(rs.balance)
if (balance_sig !== last_balance_sig) {
get('logger').info('kraken balance', 'balance'.grey, n(rs.balance[rs.asset]).format('0.000').white, rs.asset.grey, n(rs.balance[rs.currency]).format('0.00').yellow, rs.currency.grey, {feed: 'exchange'})
last_balance_sig = balance_sig
}
})
if (first_run) {
sync_start_balance = true
}
var balance_sig = sig(rs.balance)
if (balance_sig !== last_balance_sig) {
get('logger').info('trader', c.default_selector.grey, 'New account balance:'.cyan, n(rs.balance[rs.asset]).format('0.000').white, rs.asset.grey, format_currency(rs.balance[rs.currency], rs.currency).yellow, rs.currency.grey, {feed: 'trader'})
if (!rs.real_trade_warning) {
get('logger').info('trader', c.default_selector.grey, '"Starting REAL trading! Hold on to your butts!" --Zen'.cyan, {feed: 'trader'})
rs.real_trade_warning = true
}
last_balance_sig = balance_sig
}
cb()
// client.getAccounts(function (err, resp, accounts) {
// if (err) throw err
// if (resp.statusCode !== 200) {
// console.error(accounts)
// get('logger').error('non-200 status from exchange: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: accounts}})
// return cb()
// }
// rs.balance = {}
// accounts.forEach(function (account) {
// if (account.currency === rs.currency) {
// rs.balance[rs.currency] = n(account.balance).value()
// }
// else if (account.currency === rs.asset) {
// rs.balance[rs.asset] = n(account.balance).value()
// }
// })
// if (first_run) {
// sync_start_balance = true
// }
// var balance_sig = sig(rs.balance)
// if (balance_sig !== last_balance_sig) {
// get('logger').info('trader', c.default_selector.grey, '"Starting REAL trading! Hold on to your butts!" --Zen'.cyan, ' Balance:'.grey, n(rs.balance[rs.asset]).format('0.000').white, rs.asset.grey, n(rs.balance[rs.currency]).format('0.00').yellow, rs.currency.grey, {feed: 'exchange'})
// last_balance_sig = balance_sig
// }
// cb()
// })
},
// record market price, balance, roi and stats
function (tick, trigger, rs, cb) {
// note the last close price
var market_price = o(tick, rs.selector + '.close')
// sometimes the tick won't have a close price for this selector.
// keep old close price in memory.
if (market_price) {
rs.market_price = market_price
}
if (tick.size !== rs.check_period) {
return cb()
}
delete rs.lookback_warning
rs.ticks || (rs.ticks = 0)
rs.progress || (rs.progress = 0)
if (!rs.market_price) {
//get('logger').info('trader', ('no close price for tick ' + tick.id).red, {feed: 'trader'})
return cb()
}
if (!rs.balance) {
// start with start_balance, neutral position
rs.balance = {}
rs.balance[rs.currency] = n(rs.start_balance).divide(2).value()
rs.balance[rs.asset] = n(rs.start_balance).divide(2).divide(rs.market_price).value()
}
rs.consolidated_balance = n(rs.balance[rs.currency]).add(n(rs.balance[rs.asset]).multiply(rs.market_price)).value()
if (sync_start_balance) {
rs.start_balance = rs.consolidated_balance
sync_start_balance = false
}
rs.roi = n(rs.consolidated_balance).divide(rs.start_balance).value()
rs.ticks++
cb()
},
// calculate first rsi from ticks lookback
function (tick, trigger, rs, cb) {
var rsi_tick_id = tb(tick.time).resize(rs.rsi_period).toString()
if (rs.rsi && rs.rsi_tick_id && rs.rsi_tick_id !== rsi_tick_id) {
// rsi period turnover. record last rsi for smoothing.
rs.last_rsi = JSON.parse(JSON.stringify(rs.rsi))
rs.rsi.samples++
//console.error('last rsi', rs.last_rsi)
}
rs.rsi_tick_id = rsi_tick_id
cb()
},
function (tick, trigger, rs, cb) {
if (rs.first_rsi) {
return cb()
}
// calculate first rsi
//console.error('computing RSI', tick.id)
var bucket = tb(tick.time).resize(rs.rsi_period)
var params = {
query: {
app: get('app_name'),
size: rs.rsi_period,
time: {
$lt: bucket.toMilliseconds()
}
},
limit: rs.rsi_query_limit,
sort: {
time: -1
}
}
params.query[rs.selector] = {$exists: true}
get('ticks').select(params, function (err, lookback) {
if (err) return cb(err)
var missing = false
if (lookback.length < rs.rsi_periods) {
if (!rs.lookback_warning) {
get('logger').info('trader', c.default_selector.grey, ('need more historical data, only have ' + lookback.length + ' of ' + rs.rsi_periods + ' ' + rs.rsi_period + ' ticks').yellow)
}
rs.lookback_warning = true
return cb()
}
bucket.subtract(1)
lookback.forEach(function (tick) {
while (bucket.toMilliseconds() > tick.time) {
get('logger').info('trader', c.default_selector.grey, ('missing RSI tick: ' + get_timestamp(bucket.toMilliseconds())).red)
missing = true
bucket.subtract(1)
}
//get('logger').info('trader', 'RSI tick OK:'.grey, get_timestamp(bucket.toMilliseconds()).green)
bucket.subtract(1)
})
if (missing) {
if (!rs.missing_warning) {
get('logger').info('trader', c.default_selector.grey, 'missing tick data, RSI might be inaccurate. Try running `zenbot map --backfill` or wait for 3.6 for the new `zenbot repair` tool.'.red)
}
rs.missing_warning = true
}
if (!rs.missing_warning && !rs.rsi_complete_warning) {
get('logger').info('trader', c.default_selector.grey, ('historical data OK! computing initial RSI from last ' + lookback.length + ' ' + rs.rsi_period + ' ticks').green)
rs.rsi_complete_warning = true
}
withLookback(lookback.reverse())
})
function withLookback (lookback) {
var init_lookback = lookback.slice(0, rs.rsi_periods + 1)
var smooth_lookback = lookback.slice(rs.rsi_periods + 1)
var de = o(init_lookback.pop(), rs.selector)
var r = {}
r.samples = init_lookback.length
if (r.samples < rs.rsi_periods) {
return cb()
}
r.close = de.close
r.last_close = o(init_lookback[r.samples - 1], rs.selector).close
r.current_gain = r.close > r.last_close ? n(r.close).subtract(r.last_close).value() : 0
r.current_loss = r.close < r.last_close ? n(r.last_close).subtract(r.close).value() : 0
var prev_close = 0
var gain_sum = init_lookback.reduce(function (prev, curr) {
curr = o(curr, rs.selector)
if (!prev_close) {
prev_close = curr.close
return 0
}
var gain = curr.close > prev_close ? curr.close - prev_close : 0
prev_close = curr.close
return n(prev).add(gain).value()
}, 0)
var avg_gain = n(gain_sum).divide(r.samples).value()
prev_close = 0
var loss_sum = init_lookback.reduce(function (prev, curr) {
curr = o(curr, rs.selector)
if (!prev_close) {
prev_close = curr.close
return 0
}
var loss = curr.close < prev_close ? prev_close - curr.close : 0
prev_close = curr.close
return n(prev).add(loss).value()
}, 0)
var avg_loss = n(loss_sum).divide(r.samples).value()
r.last_avg_gain = avg_gain
r.last_avg_loss = avg_loss
r.avg_gain = n(r.last_avg_gain).multiply(rs.rsi_periods - 1).add(r.current_gain).divide(rs.rsi_periods).value()
r.avg_loss = n(r.last_avg_loss).multiply(rs.rsi_periods - 1).add(r.current_loss).divide(rs.rsi_periods).value()
if (r.avg_loss === 0) {
r.value = r.avg_gain ? 100 : 50
}
else {
r.relative_strength = n(r.avg_gain).divide(r.avg_loss).value()
r.value = n(100).subtract(n(100).divide(n(1).add(r.relative_strength))).value()
}
r.ansi = n(r.value).format('0')[r.value > 70 ? 'green' : r.value < 30 ? 'red' : 'white']
// first rsi, calculated from prev 14 ticks
rs.last_rsi = JSON.parse(JSON.stringify(r))
//console.error('first rsi', r)
rs.rsi = r
rs.first_rsi = rs.last_rsi = JSON.parse(JSON.stringify(r))
smooth_lookback.forEach(function (de) {
r.last_close = r.close
r.close = o(de, rs.selector).close
r.samples++
r.current_gain = r.close > r.last_close ? n(r.close).subtract(r.last_close).value() : 0
r.current_loss = r.close < r.last_close ? n(r.last_close).subtract(r.close).value() : 0
r.last_avg_gain = r.avg_gain
r.last_avg_loss = r.avg_loss
r.avg_gain = n(r.last_avg_gain).multiply(rs.rsi_periods - 1).add(r.current_gain).divide(rs.rsi_periods).value()
r.avg_loss = n(r.last_avg_loss).multiply(rs.rsi_periods - 1).add(r.current_loss).divide(rs.rsi_periods).value()
if (r.avg_loss === 0) {
r.value = r.avg_gain ? 100 : 50
}
else {
r.relative_strength = n(r.avg_gain).divide(r.avg_loss).value()
r.value = n(100).subtract(n(100).divide(n(1).add(r.relative_strength))).value()
}
r.ansi = n(r.value).format('0')[r.value > 70 ? 'green' : r.value < 30 ? 'red' : 'white']
rs.last_rsi = JSON.parse(JSON.stringify(r))
//console.error('smooth', r.close, r.last_close, r.ansi)
})
cb()
}
},
// calculate the smoothed rsi if we have last_rsi
function (tick, trigger, rs, cb) {
if (!rs.market_price || !rs.rsi || !rs.last_rsi) {
return cb()
}
var r = rs.rsi
//console.error('market', rs.market_price, rs.rsi)
r.close = rs.market_price
r.last_close = rs.last_rsi.close
r.current_gain = r.close > r.last_close ? n(r.close).subtract(r.last_close).value() : 0
r.current_loss = r.close < r.last_close ? n(r.last_close).subtract(r.close).value() : 0
r.last_avg_gain = rs.last_rsi.avg_gain
r.last_avg_loss = rs.last_rsi.avg_loss
r.avg_gain = n(r.last_avg_gain).multiply(rs.rsi_periods - 1).add(r.current_gain).divide(rs.rsi_periods).value()
r.avg_loss = n(r.last_avg_loss).multiply(rs.rsi_periods - 1).add(r.current_loss).divide(rs.rsi_periods).value()
if (r.avg_loss === 0) {
r.value = r.avg_gain ? 100 : 50
}
else {
r.relative_strength = n(r.avg_gain).divide(r.avg_loss).value()
r.value = n(100).subtract(n(100).divide(n(1).add(r.relative_strength))).value()
}
r.ansi = n(r.value).format('0')[r.value > 70 ? 'green' : r.value < 30 ? 'red' : 'white']
//console.error('smooth 2', r.close, r.last_close, r.ansi)
//process.exit()
cb()
},
// detect trends from rsi
function (tick, trigger, rs, cb) {
var trend
var r = rs.rsi
if (!r) {
return cb()
}
if (r.samples < rs.rsi_periods) {
if (!rs.rsi_warning) {
// get('logger').info('trader', c.default_selector.grey, (rs.rsi_period + ' RSI: not enough samples for tick ' + rs.rsi_tick_id + ': ' + rs.rsi.samples).red, {feed: 'trader'})
}
rs.rsi_warning = true
}
else {
if (r.value >= rs.rsi_up) {
trend = 'UP'
}
else if (r.value <= rs.rsi_down) {
trend = 'DOWN'
}
else {
trend = null
}
}
if (trend !== rs.trend) {
get('logger').info('trader', c.default_selector.grey, 'RSI:'.grey + r.ansi, ('trend: ' + rs.trend + ' -> ' + trend).yellow, {feed: 'trader'})
delete rs.balance_warning
delete rs.roi_warning
delete rs.rsi_warning
delete rs.delta_warning
delete rs.buy_warning
delete rs.perf_warning
delete rs.action_warning
delete rs.trend_warning
}
rs.trend = trend
cb()
},
// @todo MACD
function (tick, trigger, rs, cb) {
cb()
},
// trigger trade signals from trends
function (tick, trigger, rs, cb) {
if (tick.size !== rs.check_period) {
return cb()
}
// for run command, don't trade unless this is a new tick
if (get('command') !== 'sim' && tick.time < start) {
get('logger').info('trader', c.default_selector.grey, ('skipping historical tick ' + tick.id).grey, {feed: 'trader'})
return cb()
}
if (rs.trend) {
if (!rs.trend_warning && !rs.balance) {
get('logger').info('trader', c.default_selector.grey, ('no balance to act on trend: ' + rs.trend + '!').red, {feed: 'trader'})
rs.trend_warning = true
}
else if (!rs.trend_warning && !rs.market_price) {
get('logger').info('trader', c.default_selector.grey, ('no market_price to act on trend: ' + rs.trend + '!').red, {feed: 'trader'})
rs.trend_warning = true
}
}
rs.progress = 1
if (rs.trend && rs.balance && rs.market_price) {
var size, new_balance = {}
if (rs.trend === 'DOWN') {
// calculate sell size
size = rs.balance[rs.asset]
}
else if (rs.trend === 'UP') {
// calculate buy size
size = n(rs.balance[rs.currency]).divide(rs.market_price).value()
}
size = n(size || 0).multiply(rs.trade_pct).value()
if (rs.trend === 'DOWN') {
// SELL!
if (rs.last_sell_time && tick.time - rs.last_sell_time <= rs.min_double_wait) {
if (!rs.sell_warning) {
get('logger').info('trader', c.default_selector.grey, ('too soon to sell after sell! waiting ' + get_duration(n(rs.min_double_wait).subtract(n(tick.time).subtract(rs.last_sell_time)).multiply(1000).value())).red, {feed: 'trader'})
}
rs.sell_warning = true
return cb()
}
if (rs.last_buy_time && tick.time - rs.last_buy_time <= rs.min_reversal_wait) {
if (!rs.sell_warning) {
get('logger').info('trader', c.default_selector.grey, ('too soon to sell after buy! waiting ' + get_duration(n(rs.min_reversal_wait).subtract(n(tick.time).subtract(rs.last_buy_time)).multiply(1000).value())).red, {feed: 'trader'})
}
rs.sell_warning = true
return cb()
}
new_balance[rs.currency] = n(rs.balance[rs.currency]).add(n(size).multiply(rs.market_price)).value()
new_balance[rs.asset] = n(rs.balance[rs.asset]).subtract(size).value()
rs.op = 'sell'
if (!rs.action_warning) {
get('logger').info('trader', c.default_selector.grey, ('attempting to sell ' + n(size).format('0.00000000') + ' ' + rs.asset + ' for ' + format_currency(n(size).multiply(rs.market_price).value(), rs.currency) + ' ' + rs.currency).yellow, {feed: 'trader'})
}
rs.action_warning = true
}
else if (rs.trend === 'UP') {
// BUY!
if (rs.last_buy_time && tick.time - rs.last_buy_time <= rs.min_double_wait) {
if (!rs.buy_warning) {
get('logger').info('trader', c.default_selector.grey, ('too soon to buy after buy! waiting ' + get_duration(n(rs.min_double_wait).subtract(n(tick.time).subtract(rs.last_buy_time)).multiply(1000).value())).red, {feed: 'trader'})
}
rs.buy_warning = true
return cb()
}
if (rs.last_sell_time && tick.time - rs.last_sell_time <= rs.min_reversal_wait) {
if (!rs.buy_warning) {
get('logger').info('trader', c.default_selector.grey, ('too soon to buy after sell! waiting ' + get_duration(n(rs.min_reversal_wait).subtract(n(tick.time).subtract(rs.last_sell_time)).multiply(1000).value())).red, {feed: 'trader'})
}
rs.buy_warning = true
return cb()
}
new_balance[rs.asset] = n(rs.balance[rs.asset]).add(size).value()
new_balance[rs.currency] = n(rs.balance[rs.currency]).subtract(n(size).multiply(rs.market_price)).value()
rs.op = 'buy'
if (!rs.action_warning) {
get('logger').info('trader', c.default_selector.grey, ('attempting to buy ' + n(size).format('0.00000000') + ' ' + rs.asset + ' for ' + format_currency(n(size).multiply(rs.market_price).value(), rs.currency) + ' ' + rs.currency).yellow, {feed: 'trader'})
}
rs.action_warning = true
}
else {
// unknown trend
get('logger').info('trader', c.default_selector.grey, ('unkown trend (' + rs.trend + ') aborting trade!').red, {feed: 'trader'})
return cb()
}
// min size
if (!size || size < rs.min_trade) {
if (!rs.balance_warning) {
get('logger').info('trader', c.default_selector.grey, 'trend: '.grey, rs.trend, ('not enough funds (' + (rs.op === 'sell' ? n(size).format('0.00000000') : format_currency(rs.balance[rs.currency], rs.currency)) + ' ' + (rs.op === 'sell' ? rs.asset : rs.currency) + ') to execute min. ' + rs.op + ' ' + rs.min_trade + ', aborting trade!').red, {feed: 'trader'})
}
rs.balance_warning = true
return cb()
}
// fee calc
rs.fee = n(size).multiply(rs.market_price).multiply(rs.fee_pct).value()
new_balance[rs.currency] = n(new_balance[rs.currency]).subtract(rs.fee).value()
// consolidate balance
rs.new_end_balance = n(new_balance[rs.currency]).add(n(new_balance[rs.asset]).multiply(rs.market_price)).value()
rs.new_roi = n(rs.new_end_balance).divide(rs.start_balance).value()
rs.new_roi_delta = n(rs.new_roi).subtract(rs.roi || 0).value()
if (rs.op === 'buy') {
// % drop
rs.performance = rs.last_sell_price ? n(rs.last_sell_price).subtract(rs.market_price).divide(rs.last_sell_price).value() : null
}
else {
// % gain
rs.performance = rs.last_buy_price ? n(rs.market_price).subtract(rs.last_buy_price).divide(rs.last_buy_price).value() : null
}
if (rs.min_performance && rs.performance !== null && rs.performance < rs.min_performance) {
if (!rs.perf_warning) {
get('logger').info('trader', c.default_selector.grey, ('aborting ' + rs.op + ' due to low perf. = ' + n(rs.performance).format('0.000')).red, {feed: 'trader'})
}
rs.perf_warning = true
return cb()
}
if (rs.op === 'buy') {
rs.waited = rs.last_sell_time ? get_duration(n(tick.time).subtract(rs.last_sell_time).multiply(1000).value()) : null
rs.last_buy_time = tick.time
}
else {
rs.waited = rs.last_buy_time ? get_duration(n(tick.time).subtract(rs.last_buy_time).multiply(1000).value()) : null
rs.last_sell_time = tick.time
}
rs.performance_scores || (rs.performance_scores = [])
rs.performance_scores.push(rs.performance)
var performance_sum = rs.performance_scores.reduce(function (prev, curr) {
return prev + curr
}, 0)
rs.performance_avg = n(performance_sum).divide(rs.performance_scores.length).value()
rs.balance = new_balance
rs.end_balance = rs.new_end_balance
rs.roi = rs.new_roi
rs.num_trades || (rs.num_trades = 0)
rs.num_trades++
var trade = {
type: rs.op,
asset: rs.asset,
currency: rs.currency,
exchange: rs.exchange,
price: rs.market_price,
fee: rs.fee,
market: true,
size: size,
rsi: rs.rsi.value,
roi: rs.roi,
roi_delta: rs.new_roi_delta,
performance: rs.performance,
waited: rs.waited,
balance: new_balance,
end_balance: rs.new_end_balance
}
trigger(trade)
if (client) {
const order = {
// pair: 'XXBTZUSD',
pair: rs.asset+''+rs.currency,
type: rs.op,
ordertype: 'market', // market
//price: 0.01, //optional (in second currency)
volume: size //(first value)
}
client.api('AddOrder', order, function(err, data) {
if(err) {
console.log(err)
}
else {
console.log(data.result)
onOrder(err, data.result)
}
})
// var params = {
// type: 'market',
// size: n(size).format('0.000000'),
// product_id: rs.asset + '-' + rs.currency
// }
// client[rs.op](params, function (err, resp, order) {
// onOrder(err, resp, order)
// })
}
else if (!rs.sim_warning) {
get('logger').info('trader', c.default_selector.grey, ('Relax! This is a simulated trade! No real transaction will take place. --Zen').yellow, {feed: 'trader'})
rs.sim_warning = true
}
if (rs.op === 'buy') {
rs.last_buy_price = rs.market_price
}
else {
rs.last_sell_price = rs.market_price
}
rs.last_op = rs.op
}
cb()
},
function (tick, trigger, rs, cb) {
first_run = false
cb()
}
// END DEFAULT TRADE LOGIC
]
}
thank's...and the last one, your config_btc_usd.js ?
if you change something somewhere else....
var c = module.exports = require('./config')
c.assets = [
"XXBT"
]
c.currencies = [
"ZUSD",
"XXBT"
]
// default selector for indicators, etc
c.default_selector = "kraken.XXBT-ZUSD"
it's alive !!!!!
certainly an error in my default_logic.js.
Thank's a lot
Thank you for help, grigio.
It works for me too. Seems c.assets and c.currencies in config_btc_usd.js was the issue.
Is your last posted logic is less than 3.5.15 (rsi fix) version?
@Sorrow2 the last logic attached is adapted from the current one in zenbot master.
New error:
[ trader] kraken.XXBT-ZEUR No trader API key provided. Starting in advisor mode. --Zen
but i wrote my API key and Private key in default_logic.js....
I missed something ?
In default_logic there is:
// sync balance if key is present and we're in the run command
function (tick, trigger, rs, cb) {
if (get('command') !== 'run' || !c.gdax_key) {
So, if we don't give gdax_key.....
i propose:
// sync balance if key is present and we're in the run command
function (tick, trigger, rs, cb) {
if (get('command') !== 'run') {
It's appear ok, but it don't return my balance.... need to search again.
i added strings to c.gdax_key and secret in config
and it shows balance and real trades
it's your correct balance ?
yes
Everything work fine now.
Perfect for me now.
Perhaps we could make an how-to to connect with Kraken ?
@Labseb Maybe when default_logic.js will be exchange agnostic and stable, I'll cleanup the code and document it :P
BUG!
I noticed that, for some reasons to investigate, the Kraken trades stop silently to be reported after a certain time. I don't see any error also in the console logs.
In these logs I've last kraken event at 2:49 and then nothing.. but at 8:10 I restarted zenbot and I get 301 missing trades. /cc @carlos8f
And everytime I restart I lose the ROI .. 😞
Do you confirm? Do you know if it something kraken specific or it happens also for other exchanges?
It seems zenbot can usually recover from missing internet connection, but some times not and it gets stuck.
09/02/2016 08:11:07 AM CEST [ runner] m24546610 running [link]
09/02/2016 08:11:03 AM CEST [ kraken] m24546610 301 trades. 09/02/2016 08:10:55 AM CEST SELL 148.647 at 508.520 XXBT/ZEUR [link]
09/02/2016 08:10:59 AM CEST [ kraken] m24546610 301 trades. 09/02/2016 08:10:55 AM CEST SELL 148.647 at 508.520 XXBT/ZEUR [link]
09/02/2016 08:10:57 AM CEST [ launcher] cmd `reduce` booting [link]
09/02/2016 08:10:57 AM CEST [ launcher] cmd `map` booting [link]
09/02/2016 08:10:57 AM CEST [ runner] waiting for next 1d tick... [link]
09/02/2016 08:10:57 AM CEST [ runner] waiting for next 6h tick... [link]
09/02/2016 08:10:57 AM CEST [ runner] waiting for next 1h tick... [link]
09/02/2016 08:10:57 AM CEST [ runner] waiting for next 15m tick... [link]
09/02/2016 08:10:57 AM CEST [ runner] waiting for next 5m tick... [link]
09/02/2016 08:10:57 AM CEST [ runner] waiting for next 1m tick... [link]
09/02/2016 08:10:57 AM CEST [ runner] starting [link]
09/02/2016 08:10:57 AM CEST [ launcher] cmd `run` booting [link]
09/02/2016 08:10:55 AM CEST [ launcher] cmd `launch` booting [link]
09/02/2016 08:10:55 AM CEST [ launcher] cmd `launch` booting [link]
09/02/2016 08:10:43 AM CEST [ launcher] saved run_state, id = zb_run_xxbt_zeur [link]
09/02/2016 08:10:43 AM CEST [ launcher] saved run_state, id = zb_reduce [link]
09/02/2016 08:10:43 AM CEST [ launcher] saved run_state, id = zb_launch_xxbt_zeur [link]
09/02/2016 08:10:43 AM CEST [ launcher] saved run_state, id = zb_launch [link]
09/02/2016 08:10:43 AM CEST [ launcher] saved run_state, id = zb_map_xxbt_zeur [link]
09/02/2016 08:10:43 AM CEST [ launcher] cmd `run` exiting [link]
09/02/2016 08:10:43 AM CEST [ launcher] cmd `reduce` exiting [link]
09/02/2016 08:10:43 AM CEST [ launcher] cmd `launch` exiting [link]
09/02/2016 08:10:43 AM CEST [ launcher] cmd `map` exiting [link]
09/02/2016 08:10:43 AM CEST [ launcher] cmd `launch` exiting [link]
09/02/2016 08:00:08 AM CEST [ runner] waiting for next 6h tick... [link]
09/02/2016 08:00:03 AM CEST [ runner] waiting for next 6h tick... [link]
09/02/2016 08:00:03 AM CEST [ trader] kraken.XXBT-ZEUR 6h68184 running logic XXBT ZEUR [link]
09/02/2016 08:00:03 AM CEST [ runner] 6h68184 running [link]
09/02/2016 08:00:03 AM CEST [ trader] kraken.XXBT-ZEUR 6h68184 running logic XXBT ZEUR [link]
09/02/2016 08:00:03 AM CEST [ runner] 6h68184 running [link]
09/02/2016 03:00:04 AM CEST [ runner] waiting for next 1h tick... [link]
09/02/2016 03:00:04 AM CEST [ trader] kraken.XXBT-ZEUR h409104 running logic XXBT ZEUR [link]
09/02/2016 03:00:04 AM CEST [ runner] h409104 running [link]
09/02/2016 03:00:01 AM CEST [ runner] waiting for next 15m tick... [link]
09/02/2016 03:00:01 AM CEST [ trader] kraken.XXBT-ZEUR 15m1636419 running logic XXBT ZEUR [link]
09/02/2016 03:00:01 AM CEST [ runner] 15m1636419 running [link]
09/02/2016 02:50:05 AM CEST [ runner] waiting for next 5m tick... [link]
09/02/2016 02:50:05 AM CEST [ runner] waiting for next 5m tick... [link]
09/02/2016 02:50:00 AM CEST [ runner] waiting for next 5m tick... [link]
09/02/2016 02:50:00 AM CEST [ trader] kraken.XXBT-ZEUR 5m4909257 running logic XXBT ZEUR [link]
09/02/2016 02:50:00 AM CEST [ runner] 5m4909257 running [link]
09/02/2016 02:50:00 AM CEST [ trader] kraken.XXBT-ZEUR 5m4909257 running logic XXBT ZEUR [link]
09/02/2016 02:50:00 AM CEST [ runner] 5m4909257 running [link]
09/02/2016 02:49:04 AM CEST [ kraken] m24546288 7 trades. 09/02/2016 02:48:59 AM CEST BUY 3.465 at 508.753 XXBT/ZEUR [link]
I haven’t noticed any stability problems with my deployment using GDAX. It’s either Kraken-specific, or somehow your mapper or reducer process got stuck… hmmm.
On Sep 1, 2016, at 11:38 PM, Luigi Maselli [email protected] wrote:
BUG!
I noticed that, for some reasons to investigate, the Kraken trades stop silently to be reported after a certain time. I don't see any error also in the console logs.
In these logs I've last kraken event at 2:49 and then nothing.. but at 8:10 I restarted zenbot and I get 301 missing trades.
Do you confirm? Do you know if it something kraken specific or it happens also for other exchanges?
It seems zenbot can usually recover from missing internet connection, but some it gets stuck.09/02/2016 08:11:07 AM CEST [ runner] m24546610 running [link]
09/02/2016 08:11:03 AM CEST [ kraken] m24546610 301 trades. 09/02/2016 08:10:55 AM CEST SELL 148.647 at 508.520 XXBT/ZEUR [link]
09/02/2016 08:10:59 AM CEST [ kraken] m24546610 301 trades. 09/02/2016 08:10:55 AM CEST SELL 148.647 at 508.520 XXBT/ZEUR [link]
09/02/2016 08:10:57 AM CEST [ launcher] cmdreducebooting [link]
09/02/2016 08:10:57 AM CEST [ launcher] cmdmapbooting [link]
09/02/2016 08:10:57 AM CEST [ runner] waiting for next 1d tick... [link]
09/02/2016 08:10:57 AM CEST [ runner] waiting for next 6h tick... [link]
09/02/2016 08:10:57 AM CEST [ runner] waiting for next 1h tick... [link]
09/02/2016 08:10:57 AM CEST [ runner] waiting for next 15m tick... [link]
09/02/2016 08:10:57 AM CEST [ runner] waiting for next 5m tick... [link]
09/02/2016 08:10:57 AM CEST [ runner] waiting for next 1m tick... [link]
09/02/2016 08:10:57 AM CEST [ runner] starting [link]
09/02/2016 08:10:57 AM CEST [ launcher] cmdrunbooting [link]
09/02/2016 08:10:55 AM CEST [ launcher] cmdlaunchbooting [link]
09/02/2016 08:10:55 AM CEST [ launcher] cmdlaunchbooting [link]
09/02/2016 08:10:43 AM CEST [ launcher] saved run_state, id = zb_run_xxbt_zeur [link]
09/02/2016 08:10:43 AM CEST [ launcher] saved run_state, id = zb_reduce [link]
09/02/2016 08:10:43 AM CEST [ launcher] saved run_state, id = zb_launch_xxbt_zeur [link]
09/02/2016 08:10:43 AM CEST [ launcher] saved run_state, id = zb_launch [link]
09/02/2016 08:10:43 AM CEST [ launcher] saved run_state, id = zb_map_xxbt_zeur [link]09/02/2016 08:10:43 AM CEST [ launcher] cmd
runexiting [link]
09/02/2016 08:10:43 AM CEST [ launcher] cmdreduceexiting [link]
09/02/2016 08:10:43 AM CEST [ launcher] cmdlaunchexiting [link]
09/02/2016 08:10:43 AM CEST [ launcher] cmdmapexiting [link]
09/02/2016 08:10:43 AM CEST [ launcher] cmdlaunchexiting [link]
09/02/2016 08:00:08 AM CEST [ runner] waiting for next 6h tick... [link]
09/02/2016 08:00:03 AM CEST [ runner] waiting for next 6h tick... [link]
09/02/2016 08:00:03 AM CEST [ trader] kraken.XXBT-ZEUR 6h68184 running logic XXBT ZEUR [link]
09/02/2016 08:00:03 AM CEST [ runner] 6h68184 running [link]
09/02/2016 08:00:03 AM CEST [ trader] kraken.XXBT-ZEUR 6h68184 running logic XXBT ZEUR [link]
09/02/2016 08:00:03 AM CEST [ runner] 6h68184 running [link]
09/02/2016 03:00:04 AM CEST [ runner] waiting for next 1h tick... [link]
09/02/2016 03:00:04 AM CEST [ trader] kraken.XXBT-ZEUR h409104 running logic XXBT ZEUR [link]
09/02/2016 03:00:04 AM CEST [ runner] h409104 running [link]
09/02/2016 03:00:01 AM CEST [ runner] waiting for next 15m tick... [link]
09/02/2016 03:00:01 AM CEST [ trader] kraken.XXBT-ZEUR 15m1636419 running logic XXBT ZEUR [link]
09/02/2016 03:00:01 AM CEST [ runner] 15m1636419 running [link]
09/02/2016 02:50:05 AM CEST [ runner] waiting for next 5m tick... [link]
09/02/2016 02:50:05 AM CEST [ runner] waiting for next 5m tick... [link]
09/02/2016 02:50:00 AM CEST [ runner] waiting for next 5m tick... [link]
09/02/2016 02:50:00 AM CEST [ trader] kraken.XXBT-ZEUR 5m4909257 running logic XXBT ZEUR [link]
09/02/2016 02:50:00 AM CEST [ runner] 5m4909257 running [link]
09/02/2016 02:50:00 AM CEST [ trader] kraken.XXBT-ZEUR 5m4909257 running logic XXBT ZEUR [link]
09/02/2016 02:50:00 AM CEST [ runner] 5m4909257 running [link]
09/02/2016 02:49:04 AM CEST [ kraken] m24546288 7 trades. 09/02/2016 02:48:59 AM CEST BUY 3.465 at 508.753 XXBT/ZEUR [link]—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
I forgot to say that my connection is unstable, sometimes I've slow latency but also Kraken is buggy yesterday I got a lot clodflare pages instead of the actual API response.
@carlos8f is there a way to recover the ROI from the previous session? or a better way to deal with this situation without losing the ROI? Thanks
@grigio if you know what your start balance was, you can recover the ROI calculation with:
use zenbrain
var rs = db.run_states.findOne({_id: 'zb_run_xxbt_zuer'})
rs.start_balance = (consolidated balance)
db.run_states.save(rs)
as a note, the ROI reset I'm probably going to make configurable in 3.6 so you can decide when/if you want it reset
After several hours of usage I've this issue https://github.com/carlos8f/zenbot/issues/9#issuecomment-244295366 @Labseb @Sorrow2 do you confirm?
i confirm, same problem. need to restart it
Got an error for a few days, you know what maybe wrong? Tx
`crypto.js:67
this._handle.update(data, encoding);
^
TypeError: Data must be a string or a buffer
at TypeError (native)
at Hash.update (crypto.js:67:16)
at module.exports (/home/zenbot/zenbot/node_modules/sig/index.js:5:36)
at /home/zenbot/zenbot/kraken_logic.js:185:27
at Immediate.doNext [as _onImmediate] (/home/zenbot/zenbot/node_modules/zenbrain/utils/apply_funcs.js:10:12)
at tryOnImmediate (timers.js:543:15)
at processImmediate [as _immediateCallback] (timers.js:523:5)`
UPDATE: the --backfill startup option solved in fact the RSI problem.
The message " missing tick data, RSI might be inaccurate. Try running zenbot map --backfill or wait for 3.6 for the new zenbot repair tool." was shown only after the the key and secret were removed
Zenbot 4 is out, so I'm cleaning up 3.x issues. Please use and test 4, thanks!
Most helpful comment
it's alive !!!!!
certainly an error in my default_logic.js.
Thank's a lot