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

Bitfinex support #162

Closed
wants to merge 20 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
70 changes: 48 additions & 22 deletions conf-sample.js
Original file line number Diff line number Diff line change
@@ -1,57 +1,83 @@
var c = module.exports = {}

// COMMONLY TWEAKED VARIABLES:
// mongo configuration
c.mongo = {}
c.mongo.host = 'localhost'
c.mongo.port = 27017
c.mongo.db = 'zenbot4'
c.mongo.username = null
c.mongo.password = null

// default selector. only used if omitting [selector] argument from a command.
c.selector = 'gdax.BTC-USD'
// name of default trade strategy
c.strategy = 'trend_ema'

// Exchange API keys:

// to enable GDAX trading, enter your API credentials:
c.gdax = {}
c.gdax.key = 'YOUR-API-KEY'
c.gdax.b64secret = 'YOUR-BASE64-SECRET'
c.gdax.passphrase = 'YOUR-PASSPHRASE'

// to enable Poloniex trading, enter your API credentials:
c.poloniex = {}
c.poloniex.key = 'YOUR-API-KEY'
c.poloniex.secret = 'YOUR-SECRET'

// to enable Bitfinex trading, enter your API credentials:
c.bitfinex = {}
c.bitfinex.key = 'YOUR-API-KEY'
c.bitfinex.secret = 'YOUR-SECRET'
// May use 'exchange' or 'trading' wallet balances. However margin trading may not work...read the API documentation.
c.bitfinex.wallet = 'exchange'

// Optional stop-order triggers:

// sell if price drops below this % of bought price (0 to disable)
c.sell_stop_pct = 0
// buy if price surges above this % of sold price (0 to disable)
c.buy_stop_pct = 0
// enable trailing sell stop when reaching this % profit (0 to disable. note: in extreme bull markets, turn this off for max profit!)
c.profit_stop_enable_pct = 10
// enable trailing sell stop when reaching this % profit (0 to disable)
c.profit_stop_enable_pct = 0
// maintain a trailing stop this % below the high-water mark of profit
c.profit_stop_pct = 1
// avoid selling at a loss below this pct
c.max_sell_loss_pct = 25

// Order execution rules:

// avoid trading at a slippage above this pct
c.max_slippage_pct = 2
c.max_slippage_pct = 5
// buy with this % of currency balance
c.buy_pct = 99
// sell with this % of asset balance
c.sell_pct = 99
// ms to adjust non-filled order after
c.order_adjust_time = 30000
// avoid selling at a loss below this pct
c.max_sell_loss_pct = 25
// ms to poll order status
c.order_poll_time = 5000
// ms to wait for settlement (after an order cancel)
c.wait_for_settlement = 5000
// ms to wait for settlement (after a funds on hold error)
c.wait_more_for_settlement = 60000
// % to mark up or down price for orders
c.markup_pct = 0

// LESS-COMMONLY TWEAKED VARAIBLES:
// Misc options:

// mongo configuration
c.mongo_host = 'localhost'
c.mongo_port = 27017
c.mongo_db = 'zenbot4'
c.mongo_username = null
c.mongo_password = null
// default # days for backfill and sim commands
c.days = 90
// fee assessed for market-type orders. (note: zenbot normally attempts to use limit-type orders to avoid fees)
c.fee_pct = 0.25
// ms to poll new trades at
c.poll_trades = 30000
// amount of currency to start simulations with
c.currency_capital = 1000
// amount of asset to start simulations with
c.asset_capital = 0
// ms to poll order status
c.order_poll_time = 5000
// ms to adjust non-filled order after
c.order_adjust_time = 30000
// for sim, reverse time at the end of the graph, normalizing buy/hold to 0
c.symmetrical = false
// number of periods to calculate RSI at
c.rsi_periods = 14
// ms to wait for settlement (after an order cancel) when funds are still on hold
c.wait_for_settlement = 5000
// period to record balances for stats
c.balance_snapshot_period = '1h'
c.balance_snapshot_period = '15m'
6 changes: 6 additions & 0 deletions extensions/bitfinex/_codemap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
_ns: 'zenbot',

'exchanges.bitfinex': require('./exchange'),
'exchanges.list[]': '#exchanges.bitfinex'
}
135 changes: 135 additions & 0 deletions extensions/bitfinex/exchange.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
var BFX = require('bitfinex-api-node')
, _ = require('lodash')
, path = require('path')
, n = require('numbro')

module.exports = function container (get, set, clear) {
var c = get('conf')

var public_client, authed_client

function publicClient () {
if (!public_client) public_client = new BFX.APIRest()
return public_client
}

function authedClient () {
if (!authed_client) {
if (!c.bitfinex.key || c.bitfinex.key === 'YOUR-API-KEY') {
throw new Error('please configure your Bitfinex credentials in ' + path.resolve(__dirname, 'conf.js'))
}
authed_client = new BFX.APIRest(c.bitfinex.key, c.bitfinex.secret)
}
return authed_client
}

function joinProduct (product_id) {
return product_id.split('-')[0] + '' + product_id.split('-')[1]
}

return {
name: 'bitfinex',
// historyScan: 'backward',
makerFee: 0.1,

getProducts: function () {
return require('./products.json')
},

getTrades: function (opts, cb) {
var client = publicClient()
var args = joinProduct(opts.product_id)
// var path = args.pair;
// if(opts.from)
// path += '?limit_trades=49999';
client.trades(args, function (err, body) {
if (err) return cb(err)
var trades = _.map(body, function(trade) {
return {
trade_id: trade.tid,
time: n(trade.timestamp).multiply(1000).value(),
size: Number(trade.amount),
price: Number(trade.price),
side: trade.type
}
})
cb(null, trades)
})
},

getBalance: function (opts, cb) {
var client = authedClient()
client.wallet_balances(function (err, body) {
if (err) return cb(err)
var balance = {asset: 0, currency: 0}
var accounts = _(body).filter(function (body) { return body.type === c.bitfinex.wallet }).forEach(function (account) {
if (account.currency.toUpperCase() === opts.currency) {
balance.currency = account.amount
balance.currency_hold = (account.amount - account.available)
}
else if (account.currency === opts.asset) {
balance.asset = account.amount
balance.asset_hold = (account.amount - account.available)
}
})
cb(null, balance)
})
},

getQuote: function (opts, cb) {
var client = publicClient()
var pair = joinProduct(opts.product_id)
client.ticker(pair, function (err, body) {
if (err) return cb(err)
cb(null, {bid: body.bid, ask: body.ask})
})
},

cancelOrder: function (opts, cb) {
var client = authedClient()
client.cancel_order(opts.order_id, function (err, body) {
if (err) return cb(err)
cb()
})
},

buy: function (opts, cb) {
var client = authedClient()
if (typeof opts.type === 'undefined') {
opts.type = 'exchange limit'
}
var pair = joinProduct(opts.product_id)
client.new_order(pair, opts.size, opts.price, 'bitfinex', 'buy', opts.type, false, function (err, body) {
if (err) return cb(err)
cb(null, body)
})
// console.log(pair, opts)
},

sell: function (opts, cb) {
var client = authedClient()
if (typeof opts.type === 'undefined') {
opts.type = 'exchange limit'
}
var pair = joinProduct(opts.product_id)
client.new_order(pair, opts.size, opts.price, 'bitfinex', 'sell', opts.type, false, function (err, body) {
if (err) return cb(err)
cb(null, body)
})
// console.log(pair, opts)
},

getOrder: function (opts, cb) {
var client = authedClient()
client.order_status(opts.order_id, function (err, body) {
if (err) return cb(err)
cb(null, body)
})
},

// return the property used for range querying.
getCursor: function (trade) {
return trade.trade_id
}
}
}
Loading