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

Commit

Permalink
CEXIO exchange (#606)
Browse files Browse the repository at this point in the history
  • Loading branch information
nedievas authored and DeviaVir committed Oct 11, 2017
1 parent d274f03 commit 3bd0add
Show file tree
Hide file tree
Showing 7 changed files with 563 additions and 11 deletions.
16 changes: 10 additions & 6 deletions conf-sample.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,20 @@ c.bitstamp.secret = 'YOUR-SECRET'
// A client ID is required on Bitstamp
c.bitstamp.client_id = 'YOUR-CLIENT-ID'

// to enable CEX.IO trading, enter your API credentials:
c.cexio = {}
c.cexio.username = 'YOUR-CLIENT-ID'
c.cexio.key = 'YOUR-API-KEY'
c.cexio.secret = 'YOUR-SECRET'

// to enable QuadrigaCX tranding, enter your API credentials:
c.quadriga = {}
c.quadriga.key = 'YOUR-API-KEY';

c.quadriga.key = 'YOUR-API-KEY'
// this is the manual secret key entered by editing the API access
// and NOT the md5 hash you see in the summary
c.quadriga.secret = 'YOUR-SECRET';

c.quadriga.secret = 'YOUR-SECRET'
// replace with the client id used at login, as a string, not number
c.quadriga.client_id = 'YOUR-CLIENT-ID';
c.quadriga.client_id = 'YOUR-CLIENT-ID'

// to enable BTC-e trading, enter your API credentials:
c.btce = {}
Expand All @@ -77,7 +81,7 @@ c.btce.secret = 'YOUR-SECRET'
// to enable Gemini trading, enter your API credentials:
c.gemini = {}
c.gemini.key = 'YOUR-API-KEY'
c.gemini.secret = 'YOUR-API-SECRET'
c.gemini.secret = 'YOUR-SECRET'
// set to false to trade on the live platform API
c.gemini.sandbox = true

Expand Down
6 changes: 6 additions & 0 deletions extensions/exchanges/cexio/_codemap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
_ns: 'zenbot',

'exchanges.cexio': require('./exchange'),
'exchanges.list[]': '#exchanges.cexio'
}
201 changes: 201 additions & 0 deletions extensions/exchanges/cexio/exchange.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
const CEX = require('cexio-api-node')
var path = require('path')
var 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 CEX().rest
}
return public_client
}

function authedClient () {
if (!authed_client) {
if (!c.cexio || !c.cexio.username || !c.cexio.key || c.cexio.key === 'YOUR-API-KEY') {
throw new Error('please configure your CEX.IO credentials in ' + path.resolve(__dirname, 'conf.js'))
}
let nonce = new Date().getTime() * 1000
authed_client = new CEX(c.cexio.username, c.cexio.key, c.cexio.secret).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(('\nCEX.IO API is down! unable to call ' + method + ', retrying in 10s').red)
}
setTimeout(function () {
exchange[method].apply(exchange, args)
}, 10000)
}

var orders = {}
var exchange = {
name: 'cexio',
historyScan: 'forward',
makerFee: 0,
takerFee: 0.2,

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

getTrades: function (opts, cb) {
var func_args = [].slice.call(arguments)
var args = opts.from
var client = publicClient()
var pair = joinProduct(opts.product_id)
client.trade_history(pair, args, function (err, body) {
if (err || typeof body === 'undefined') return retry('getTrades', func_args, err)
var trades = body.map(function (trade) {
return {
trade_id: Number(trade.tid),
time: Number(trade.date) * 1000,
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.account_balance(function (err, body) {
if (err || typeof body === 'undefined') return retry('getBalance', func_args, err)
var balance = { asset: 0, currency: 0 }
balance.currency = n(body[opts.currency].available).format('0.00000000')
balance.currency_hold = n(body[opts.currency].orders).format('0.00000000')
balance.asset = n(body[opts.asset].available).format('0.00000000')
balance.asset_hold = n(body[opts.asset].orders).format('0.00000000')
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 || typeof body === 'undefined') return retry('getQuote', func_args, err)
cb(null, { bid: String(body.bid), ask: String(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 (body === 'Order canceled') return cb()
if (err) return retry('cancelOrder', func_args, err)
cb()
})
},

buy: function (opts, cb) {
var func_args = [].slice.call(arguments)
var client = authedClient()
var pair = joinProduct(opts.product_id)
if (opts.order_type === 'taker') {
delete opts.price
delete opts.post_only
opts.size = n(opts.size).multiply(opts.orig_price).value() // CEXIO estimates asset size and uses free currency to performe margin buy
opts.type = 'market'
}
delete opts.order_type
client.place_order(pair, 'buy', opts.size, opts.price, opts.type, function (err, body) {
if (body === 'error: Error: Place order error: Insufficient funds.') {
var order = {
status: 'rejected',
reject_reason: 'balance'
}
return cb(null, order)
}
if (err) return retry('buy', func_args, err)
order = {
id: body && (body.complete === false || body.message) ? body.id : null,
status: 'open',
price: opts.price,
size: opts.size,
post_only: !!opts.post_only,
created_at: new Date().getTime(),
filled_size: '0',
ordertype: opts.order_type
}
orders['~' + body.id] = order
cb(null, order)
})
},

sell: function (opts, cb) {
var func_args = [].slice.call(arguments)
var client = authedClient()
var pair = joinProduct(opts.product_id)
if (opts.order_type === 'taker') {
delete opts.price
delete opts.post_only
opts.type = 'market'
}
delete opts.order_type
client.place_order(pair, 'sell', opts.size, opts.price, opts.type, function (err, body) {
if (body === 'error: Error: Place order error: Insufficient funds.') {
var order = {
status: 'rejected',
reject_reason: 'balance'
}
return cb(null, order)
}
if (err) return retry('buy', func_args, err)
order = {
id: body && (body.complete === false || body.message) ? body.id : null,
status: 'open',
price: opts.price,
size: opts.size,
post_only: !!opts.post_only,
created_at: new Date().getTime(),
filled_size: '0',
ordertype: opts.order_type
}
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.get_order_details(opts.order_id, function (err, body) {
console.log('status client', err, body)
if (err || typeof body === 'undefined') return retry('getOrder', func_args, err)
if (body.status === 'c') {
order.status = 'rejected'
order.reject_reason = 'canceled'
}
if (body.status === 'd' || body.status === 'cd') {
order.status = 'done'
order.done_at = new Date().getTime()
order.filled_size = n(opts.size).subtract(body.remains).format('0.00000000')
}
cb(null, order)
})
},

// return the property used for range querying.
getCursor: function (trade) {
return trade.trade_id
}
}
return exchange
}
138 changes: 138 additions & 0 deletions extensions/exchanges/cexio/products.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
[
{
"asset": "BTC",
"currency": "USD",
"min_size": "0.01",
"max_size": "30",
"increment": "0.00000001",
"label": "BTC/USD"
},
{
"asset": "ETH",
"currency": "USD",
"min_size": "0.1",
"max_size": "1000",
"increment": "0.00000001",
"label": "ETH/USD"
},
{
"asset": "BCH",
"currency": "USD",
"min_size": "0.01",
"max_size": null,
"increment": "0.00000001",
"label": "BCH/USD"
},
{
"asset": "DASH",
"currency": "USD",
"min_size": "0.01",
"max_size": null,
"increment": "0.00000001",
"label": "DASH/USD"
},
{
"asset": "BTC",
"currency": "EUR",
"min_size": "0.01",
"max_size": "30",
"increment": "0.00000001",
"label": "BTC/EUR"
},
{
"asset": "ETH",
"currency": "EUR",
"min_size": "0.1",
"max_size": null,
"increment": "0.00000001",
"label": "ETH/EUR"
},
{
"asset": "BCH",
"currency": "EUR",
"min_size": "0.01",
"max_size": null,
"increment": "0.00000001",
"label": "BCH/EUR"
},
{
"asset": "DASH",
"currency": "EUR",
"min_size": "0.01",
"max_size": null,
"increment": "0.00000001",
"label": "DASH/EUR"
},
{
"asset": "BTC",
"currency": "GBP",
"min_size": "0.01",
"max_size": null,
"increment": "0.00000001",
"label": "BTC/GBP"
},
{
"asset": "ETH",
"currency": "GBP",
"min_size": "0.1",
"max_size": null,
"increment": "0.00000001",
"label": "ETH/GBP"
},
{
"asset": "BCH",
"currency": "GBP",
"min_size": "0.01",
"max_size": null,
"increment": "0.00000001",
"label": "BCH/GBP"
},
{
"asset": "DASH",
"currency": "GBP",
"min_size": "0.01",
"max_size": null,
"increment": "0.00000001",
"label": "DASH/GBP"
},
{
"asset": "BTC",
"currency": "RUB",
"min_size": "0.01",
"max_size": null,
"increment": "0.00000001",
"label": "BTC/RUB"
},
{
"asset": "ETH",
"currency": "BTC",
"min_size": "0.1",
"max_size": "1000",
"increment": "0.00000001",
"label": "ETH/BTC"
},
{
"asset": "BCH",
"currency": "BTC",
"min_size": "0.1",
"max_size": null,
"increment": "0.00000001",
"label": "BCH/BTC"
},
{
"asset": "DASH",
"currency": "BTC",
"min_size": "0.01",
"max_size": null,
"increment": "0.00000001",
"label": "DASH/BTC"
},
{
"asset": "GHS",
"currency": "BTC",
"min_size": "1",
"max_size": null,
"increment": "0.00000001",
"label": "GHS/BTC"
}
]
Loading

0 comments on commit 3bd0add

Please # to comment.