This repository was 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
Added Binance to Zenbot #782
Merged
Merged
Changes from 3 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
dbcac99
Added Binance to Zenbot
abduegal b1a8f92
small change in the engine to make binance cancel order work
abduegal 2d6c3b6
removed the node-binance-api
abduegal e708d11
Merge remote-tracking branch 'upstream/master'
abduegal d676eae
fixed feedback for pull request.
abduegal 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 hidden or 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.binance': require('./exchange'), | ||
| 'exchanges.list[]': '#exchanges.binance' | ||
| } |
This file contains hidden or 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,256 @@ | ||
| const ccxt = require('ccxt') | ||
| , path = require('path') | ||
| , colors = require('colors') | ||
| , moment = require('moment') | ||
| , _ = require('lodash') | ||
| , 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 ccxt.binance({ 'apiKey': '', 'secret': '' }) | ||
| return public_client | ||
| } | ||
|
|
||
| function authedClient () { | ||
| if (!authed_client) { | ||
| if (!c.binance || !c.binance.key || !c.binance.key === 'YOUR-API-KEY') { | ||
| throw new Error('please configure your Binance credentials in ' + path.resolve(__dirname, 'conf.js')) | ||
| } | ||
| authed_client = new ccxt.binance({ 'apiKey': c.binance.key, 'secret': c.binance.secret }) | ||
| } | ||
| return authed_client | ||
| } | ||
|
|
||
| function joinProduct(product_id) { | ||
| return product_id.split('-')[0] + '/' + product_id.split('-')[1] | ||
| } | ||
|
|
||
| function retry (method, args, err) { | ||
| if (method !== 'getTrades') { | ||
| console.error(('\nBinance API is down! unable to call ' + method + ', retrying in 20s').red) | ||
| if (err) console.error(err) | ||
| console.error(args.slice(0, -1)) | ||
| } | ||
| setTimeout(function () { | ||
| exchange[method].apply(exchange, args) | ||
| }, 20000) | ||
| } | ||
|
|
||
| var orders = {} | ||
|
|
||
| var exchange = { | ||
| name: 'binance', | ||
| historyScan: 'forward', | ||
| makerFee: 0.1, | ||
| takerFee: 0.1, | ||
|
|
||
| getProducts: function () { | ||
| return require('./products.json') | ||
| }, | ||
|
|
||
| getTrades: function (opts, cb) { | ||
| var func_args = [].slice.call(arguments) | ||
|
|
||
| var args = {}; | ||
| if (opts.from) { | ||
| args.startTime = opts.from | ||
| } | ||
| if (opts.to) { | ||
| args.endTime = opts.to | ||
| } | ||
| if (args.startTime && !args.endTime) { | ||
| // add 12 hours | ||
| args.endTime = args.startTime + 43200000 | ||
| } | ||
| else if (args.endTime && !args.startTime) { | ||
| // subtract 12 hours | ||
| args.startTime = args.endTime - 43200000 | ||
| } | ||
|
|
||
| var client = publicClient() | ||
| client.fetchTrades(joinProduct(opts.product_id), '','', args).then(result => { | ||
| var trades = result.map(function (trade) { | ||
| return { | ||
| trade_id: trade.id, | ||
| time: trade.timestamp, | ||
| size: parseFloat(trade.amount), | ||
| price: parseFloat(trade.price), | ||
| side: trade.side | ||
| } | ||
| }) | ||
| cb(null, trades) | ||
| }).catch(function (error) { | ||
| console.error('An error occurred', error) | ||
| return retry('getTrades', func_args) | ||
| }) | ||
| }, | ||
|
|
||
| getBalance: function (opts, cb) { | ||
| var func_args = [].slice.call(arguments) | ||
| var client = authedClient() | ||
| client.fetchBalance().then(result => { | ||
| var balance = {asset: 0, currency: 0} | ||
| Object.keys(result).forEach(function (key) { | ||
| if (key === opts.currency) { | ||
| balance.currency = result[key].free + result[key].used | ||
| balance.currency_hold = result[key].used | ||
| } | ||
| if (key === opts.asset) { | ||
| balance.asset = result[key].free + result[key].used | ||
| balance.asset_hold = result[key].used | ||
| } | ||
| }) | ||
| cb(null, balance) | ||
| }) | ||
| .catch(function (error) { | ||
| console.error('An error occurred', error) | ||
| return retry('getBalance', func_args) | ||
| }) | ||
| }, | ||
|
|
||
| getQuote: function (opts, cb) { | ||
| var func_args = [].slice.call(arguments) | ||
| var client = publicClient() | ||
| client.fetchTicker(joinProduct(opts.product_id)).then(result => { | ||
| cb(null, { bid: result.bid, ask: result.ask }) | ||
| }) | ||
| .catch(function (error) { | ||
| console.error('An error occurred', error) | ||
| return retry('getQuote', func_args) | ||
| }) | ||
| }, | ||
|
|
||
| cancelOrder: function (opts, cb) { | ||
| var func_args = [].slice.call(arguments) | ||
| var client = authedClient() | ||
| client.cancelOrder(opts.order_id, joinProduct(opts.product_id)).then(function (body) { | ||
| if (body && (body.message === 'Order already done' || body.message === 'order not found')) return cb() | ||
| cb(null) | ||
| },function(err){ | ||
| if (err) return retry('cancelOrder', func_args, err) | ||
| cb() | ||
| }) | ||
| }, | ||
|
|
||
| buy: function (opts, cb) { | ||
| var func_args = [].slice.call(arguments) | ||
| var client = authedClient() | ||
| if (typeof opts.post_only === 'undefined') { | ||
| opts.post_only = true | ||
| } | ||
| opts.type = 'limit' | ||
| var args = {} | ||
| if (opts.order_type === 'taker') { | ||
| delete opts.price | ||
| delete opts.post_only | ||
| opts.type = 'market' | ||
| } else { | ||
| args.timeInForce = 'GTC' | ||
| } | ||
| opts.side = 'buy' | ||
| delete opts.order_type | ||
| var order = {} | ||
| client.createOrder(joinProduct(opts.product_id), opts.type, opts.side, this.roundToNearest(opts.size, opts), opts.price, args).then(result => { | ||
| if (result && result.message === 'Insufficient funds') { | ||
| order = { | ||
| status: 'rejected', | ||
| reject_reason: 'balance' | ||
| } | ||
| return cb(null, order) | ||
| } | ||
| order = { | ||
| id: result ? result.id : null, | ||
| status: 'open', | ||
| price: opts.price, | ||
| size: this.roundToNearest(opts.size, opts), | ||
| post_only: !!opts.post_only, | ||
| created_at: new Date().getTime(), | ||
| filled_size: '0', | ||
| ordertype: opts.order_type | ||
| } | ||
| orders['~' + result.id] = order | ||
| cb(null, order) | ||
| }).catch(function (error) { | ||
| console.error('An error occurred', error) | ||
| return retry('buy', func_args) | ||
| }) | ||
| }, | ||
|
|
||
| sell: function (opts, cb) { | ||
| var func_args = [].slice.call(arguments) | ||
| var client = authedClient() | ||
| if (typeof opts.post_only === 'undefined') { | ||
| opts.post_only = true | ||
| } | ||
| opts.type = 'limit' | ||
| var args = {} | ||
| if (opts.order_type === 'taker') { | ||
| delete opts.price | ||
| delete opts.post_only | ||
| opts.type = 'market' | ||
| } else { | ||
| args.timeInForce = 'GTC' | ||
| } | ||
| opts.side = 'sell' | ||
| delete opts.order_type | ||
| var order = {} | ||
| client.createOrder(joinProduct(opts.product_id), opts.type, opts.side, this.roundToNearest(opts.size, opts), opts.price, args).then(result => { | ||
| if (result && result.message === 'Insufficient funds') { | ||
| order = { | ||
| status: 'rejected', | ||
| reject_reason: 'balance' | ||
| } | ||
| return cb(null, order) | ||
| } | ||
| order = { | ||
| id: result ? result.id : null, | ||
| status: 'open', | ||
| price: opts.price, | ||
| size: this.roundToNearest(opts.size, opts), | ||
| post_only: !!opts.post_only, | ||
| created_at: new Date().getTime(), | ||
| filled_size: '0', | ||
| ordertype: opts.order_type | ||
| } | ||
| orders['~' + result.id] = order | ||
| cb(null, order) | ||
| }).catch(function (error) { | ||
| console.error('An error occurred', error) | ||
| return retry('buy', func_args) | ||
| }) | ||
| }, | ||
|
|
||
| roundToNearest: function(numToRound, opts) { | ||
| var numToRoundTo = _.find(this.getProducts(), { 'asset': opts.product_id.split('-')[0], 'currency': opts.product_id.split('-')[1] }).min_size | ||
| numToRoundTo = 1 / (numToRoundTo) | ||
|
|
||
| return Math.floor(numToRound * numToRoundTo) / numToRoundTo | ||
| }, | ||
|
|
||
| getOrder: function (opts, cb) { | ||
| var func_args = [].slice.call(arguments) | ||
| var client = authedClient() | ||
| var order = orders['~' + opts.order_id] | ||
| client.fetchOrder(opts.order_id, joinProduct(opts.product_id)).then(function (body) { | ||
| if (body.status !== 'open' && body.status !== 'canceled') { | ||
| order.status = 'done' | ||
| order.done_at = new Date().getTime() | ||
| order.filled_size = parseFloat(body.amount) - parseFloat(body.remaining) | ||
| return cb(null, order) | ||
| } | ||
| cb(null, order) | ||
| }, function(err) { | ||
| return retry('getOrder', func_args, err) | ||
| }) | ||
| }, | ||
|
|
||
| getCursor: function (trade) { | ||
| return (trade.time || trade) | ||
| } | ||
| } | ||
| return exchange | ||
| } | ||
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.
if (!c.binance || !c.binance.key || !c.binance.key === 'YOUR-API-KEY') {This should be:
if (!c.binance || !c.binance.key || c.binance.key === 'YOUR-API-KEY') {Because if
c.binance.key === 'YOUR-API-KEY'we should stop