This repository has been archived by the owner on Feb 15, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2k
Bitfinex extension PR #245
Merged
Merged
Changes from 6 commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
01f9ae2
Add files via upload
nedievas c7e10f9
Delete bitfinex-master.zip
nedievas 9b6760e
Create package.json
nedievas ae8abbe
final version
nedievas 70aeef5
Bitfinex API credentials
nedievas 10c5e9c
Bitfinex deps
nedievas 6c8edb5
// fix
nedievas 1ee7690
add takerFee
nedievas 65829dc
move to /
nedievas File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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' | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
const BFX = require('bitfinex-api-node') | ||
var _ = 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(null,null, {version: 1}).rest | ||
return public_client | ||
} | ||
|
||
function authedClient () { | ||
if (!authed_client) { | ||
if (!c.bitfinex.key || c.bitfinex.key === 'YOUR-API-KEY') { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no check for |
||
throw new Error('please configure your Bitfinex credentials in ' + path.resolve(__dirname, 'conf.js')) | ||
} | ||
authed_client = new BFX(c.bitfinex.key, c.bitfinex.secret, {version: 1}).rest | ||
} | ||
return authed_client | ||
} | ||
|
||
function joinProduct (product_id) { | ||
return product_id.split('-')[0] + '' + product_id.split('-')[1] | ||
} | ||
|
||
function retry (method, args) { | ||
if (method !== 'getTrades') { | ||
console.error(('\nBitfinex API is down! unable to call ' + method + ', retrying in 10s').red) | ||
} | ||
setTimeout(function () { | ||
exchange[method].apply(exchange, args) | ||
}, 10000) | ||
} | ||
|
||
var orders = {} | ||
var exchange = { | ||
name: 'bitfinex', | ||
// historyScan: 'backward', | ||
makerFee: 0.1, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. could you add |
||
|
||
getProducts: function () { | ||
return require('./products.json') | ||
}, | ||
|
||
getTrades: function (opts, cb) { | ||
var func_args = [].slice.call(arguments) | ||
var client = publicClient() | ||
var args = joinProduct(opts.product_id) | ||
client.trades(args, function (err, body) { | ||
if (err) return retry('getTrades', func_args, err) | ||
var trades = body.map(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 func_args = [].slice.call(arguments) | ||
var client = authedClient() | ||
client.wallet_balances(function (err, body) { | ||
if (err) return retry('getBalance', func_args, 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.toUpperCase() === opts.asset) { | ||
balance.asset = account.amount | ||
balance.asset_hold = (account.amount - account.available) | ||
} | ||
}) | ||
cb(null, balance) | ||
}) | ||
}, | ||
|
||
getQuote: function (opts, cb) { | ||
var func_args = [].slice.call(arguments) | ||
var client = publicClient() | ||
var pair = joinProduct(opts.product_id) | ||
client.ticker(pair, function (err, body) { | ||
if (err) return retry('getQuote', func_args, err) | ||
cb(null, { bid : body.bid, ask : body.ask }) | ||
}) | ||
}, | ||
|
||
cancelOrder: function (opts, cb) { | ||
var func_args = [].slice.call(arguments) | ||
var client = authedClient() | ||
client.cancel_order(opts.order_id, function (err, body) { | ||
if (err) return retry('cancelOrder', func_args, err) | ||
cb() | ||
}) | ||
}, | ||
|
||
buy: function (opts, cb) { | ||
var func_args = [].slice.call(arguments) | ||
var client = authedClient() | ||
if (c.bitfinex.wallet === 'exchange' && typeof opts.type === 'undefined') { | ||
opts.type = 'exchange limit' | ||
} | ||
else if (c.bitfinex.wallet === 'trading' && typeof opts.type === 'undefined') { | ||
opts.type = 'limit' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ref #233 again, could you add a check for |
||
} | ||
var symbol = joinProduct(opts.product_id) | ||
var amount = opts.size | ||
var price = opts.price | ||
var exchange = 'bitfinex' | ||
var side = 'buy' | ||
var type = opts.type | ||
var is_hidden = false | ||
var is_postonly = opts.post_only | ||
var params = { | ||
symbol, | ||
amount, | ||
price, | ||
exchange, | ||
side, | ||
type, | ||
is_hidden, | ||
is_postonly | ||
} | ||
client.make_request('order/new', params, function (err, body) { | ||
var order = { | ||
id: body && body.is_live === true ? body.id : null, | ||
status: 'open', | ||
price: opts.price, | ||
size: opts.size, | ||
post_only: !!opts.post_only, | ||
created_at: new Date().getTime(), | ||
filled_size: '0' | ||
} | ||
if (err && err.match(/Error: Invalid order: not enough exchange balance$/)) { | ||
status: 'rejected' | ||
reject_reason: 'balance' | ||
return cb(null, order) | ||
} | ||
if (err) return retry('buy', func_args, err) | ||
orders['~' + body.id] = order | ||
cb(null, order) | ||
}) | ||
}, | ||
|
||
sell: function (opts, cb) { | ||
var func_args = [].slice.call(arguments) | ||
var client = authedClient() | ||
if (c.bitfinex.wallet === 'exchange' && typeof opts.type === 'undefined') { | ||
opts.type = 'exchange limit' | ||
} | ||
else if (c.bitfinex.wallet === 'trading' && typeof opts.type === 'undefined') { | ||
opts.type = 'limit' | ||
} | ||
var symbol = joinProduct(opts.product_id) | ||
var amount = opts.size | ||
var price = opts.price | ||
var exchange = 'bitfinex' | ||
var side = 'sell' | ||
var type = opts.type | ||
var is_hidden = false | ||
var is_postonly = opts.post_only | ||
var params = { | ||
symbol, | ||
amount, | ||
price, | ||
exchange, | ||
side, | ||
type, | ||
is_hidden, | ||
is_postonly | ||
} | ||
client.make_request('order/new', params, function (err, body) { | ||
var order = { | ||
id: body && body.is_live === true ? body.id : null, | ||
status: 'open', | ||
price: opts.price, | ||
size: opts.size, | ||
post_only: !!opts.post_only, | ||
created_at: new Date().getTime(), | ||
filled_size: '0' | ||
} | ||
if (err && err.match(/Error: Invalid order: not enough exchange balance$/)) { | ||
status: 'rejected' | ||
reject_reason: 'balance' | ||
return cb(null, order) | ||
} | ||
if (err) return retry('sell', func_args, err) | ||
orders['~' + body.id] = order | ||
cb(null, order) | ||
}) | ||
}, | ||
|
||
getOrder: function (opts, cb) { | ||
var func_args = [].slice.call(arguments) | ||
var order = orders['~' + opts.order_id] | ||
var client = authedClient() | ||
client.order_status(opts.order_id, function (err, body) { | ||
if (err) return retry('getOrder', func_args, err) | ||
if (!body.id) { | ||
return cb('Order not found') | ||
} | ||
if (body.is_cancelled === true && body.is_live === false) { | ||
order.status = 'rejected' | ||
order.reject_reason = 'post only' | ||
order.done_at = new Date().getTime() | ||
return cb(null, order) | ||
} | ||
if (body.is_live === false) { | ||
order.status = 'done' | ||
order.done_at = new Date().getTime() | ||
order.filled_size = body.original_amount - body.executed_amount | ||
return cb(null, order) | ||
} | ||
cb(null, order) | ||
}) | ||
}, | ||
|
||
// return the property used for range querying. | ||
getCursor: function (trade) { | ||
return trade.trade_id | ||
} | ||
} | ||
return exchange | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing leading
//