diff --git a/README.md b/README.md index f3fe634c90..0059566831 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Zenbot is a command-line cryptocurrency trading bot using Node.js and MongoDB. I ## Quick-start -### 1. Requirements: Linux or OSX or Docker, [Node.js](https://nodejs.org/) and [MongoDB](https://www.mongodb.com/). +### 1. Requirements: Windows, Linux or OSX or Docker, [Node.js](https://nodejs.org/) and [MongoDB](https://www.mongodb.com/). ### 2. Install zenbot 4: @@ -95,6 +95,12 @@ docker-compose build docker-compose up (-d if you don't want to see the log) ``` +If you are running windows use the following command + +``` +docker-compose --file=docker-compose-windows.yml up +``` + If you wish to run commands (e.g. backfills, list-selectors), you can run this separate command after a successful `docker-compose up -d`: ``` diff --git a/commands/sim.js b/commands/sim.js index 18ad6dbd3f..0369488df3 100644 --- a/commands/sim.js +++ b/commands/sim.js @@ -95,12 +95,14 @@ module.exports = function container (get, set, clear) { }) var options_json = JSON.stringify(options, null, 2) output_lines.push(options_json) - s.my_trades.push({ - price: s.period.close, - size: s.balance.asset, - type: 'sell', - time: s.period.time - }) + if (s.my_trades.length) { + s.my_trades.push({ + price: s.period.close, + size: s.balance.asset, + type: 'sell', + time: s.period.time + }) + } s.balance.currency = n(s.balance.currency).add(n(s.period.close).multiply(s.balance.asset)).format('0.00000000') s.balance.asset = 0 s.lookback.unshift(s.period) diff --git a/commands/trade.js b/commands/trade.js index fc6c869811..9a539090f2 100644 --- a/commands/trade.js +++ b/commands/trade.js @@ -96,7 +96,8 @@ module.exports = function container (get, set, clear) { var periods = get('db.periods') console.log('fetching pre-roll data:') - var backfiller = spawn(path.resolve(__dirname, '..', 'zenbot.sh'), ['backfill', so.selector, '--days', days]) + var zenbot_cmd = process.platform === 'win32' ? 'zenbot.bat' : 'zenbot.sh'; // Use 'win32' for 64 bit windows too + var backfiller = spawn(path.resolve(__dirname, '..', zenbot_cmd), ['backfill', so.selector, '--days', days]) backfiller.stdout.pipe(process.stdout) backfiller.stderr.pipe(process.stderr) backfiller.on('exit', function (code) { @@ -152,28 +153,34 @@ module.exports = function container (get, set, clear) { forwardScan() setInterval(forwardScan, c.poll_trades) readline.emitKeypressEvents(process.stdin) - process.stdin.setRawMode(true) + if (process.stdin.setRawMode) {process.stdin.setRawMode(true) process.stdin.on('keypress', function (key, info) { - if (key === 'b' && !info.ctrl) { + if (key === 'b' && !info.ctrl ) { engine.executeSignal('buy') - } else if (key === 'B' && !info.ctrl) { + } + else if (key === 'B' && !info.ctrl) { engine.executeSignal('buy', null, null, false, true) - } else if (key === 's' && !info.ctrl) { + } + else if (key === 's' && !info.ctrl) { engine.executeSignal('sell') - } else if (key === 'S' && !info.ctrl) { + } + else if (key === 'S' && !info.ctrl) { engine.executeSignal('sell', null, null, false, true) - } else if ((key === 'c' || key === 'C') && !info.ctrl) { + } + else if ((key === 'c' || key === 'C') && !info.ctrl) { delete s.buy_order delete s.sell_order - } else if ((key === 'm' || key === 'M') && !info.ctrl) { + } + else if ((key === 'm' || key === 'M') && !info.ctrl) { so.manual = !so.manual console.log('\nmanual mode: ' + (so.manual ? 'ON' : 'OFF') + '\n') - } else if (info.name === 'c' && info.ctrl) { + + }else if (info.name === 'c' && info.ctrl) { // @todo: cancel open orders before exit console.log() process.exit() } - }) + })} }) }) return diff --git a/docker-compose-windows.yml b/docker-compose-windows.yml new file mode 100644 index 0000000000..db5c62c486 --- /dev/null +++ b/docker-compose-windows.yml @@ -0,0 +1,21 @@ +server: + build: . + volumes: + - .:/app + - /app/node_modules + links: + - mongodb + command: ./zenbot.sh trade --paper + restart: always + +mongodb: + image: mongo:latest + volumes_from: + - mongodb-data + command: mongod --smallfiles + +mongodb-data: + image: mongo:latest + volumes: + - /data/db + command: "true" diff --git a/docs/developers.md b/docs/developers.md index f9132463c9..5b023d26cb 100644 --- a/docs/developers.md +++ b/docs/developers.md @@ -153,7 +153,7 @@ getQuote: function (opts, cb) ``` Called from: - https://github.com/carlos8f/zenbot/blob/master/lib/engine.js -- https://github.com/carlos8f/zenbot/blob/master/commands/buyjs +- https://github.com/carlos8f/zenbot/blob/master/commands/buy.js - https://github.com/carlos8f/zenbot/blob/master/commands/sell.js Input: diff --git a/extensions/exchanges/quadriga/exchange.js b/extensions/exchanges/quadriga/exchange.js index ffcd610b3a..399d1a75d2 100644 --- a/extensions/exchanges/quadriga/exchange.js +++ b/extensions/exchanges/quadriga/exchange.js @@ -50,6 +50,7 @@ module.exports = function container (get, set, clear) { name: 'quadriga', historyScan: 'backward', makerFee: 0.5, + takerFee: 0.5, getProducts: function () { return require('./products.json') @@ -63,22 +64,24 @@ module.exports = function container (get, set, clear) { } var client = publicClient() - client.api('transactions', args, function (err, trades) { + client.api('transactions', args, function (err, body) { if (!shownWarnings) { - console.log('please note: the quadriga api does not support backfilling (trade/paper only).') - console.log('please note: make sure to set the period to 1h') + console.log('please note: the quadriga api does not support backfilling.') + console.log('please note: periods should be set to 1h or less.'); shownWarnings = true } if (err) return retry('getTrades', func_args, err) - if (trades.error) return retry('getTrades', func_args, trades.error) + if (body.error) return retry('getTrades', func_args, trades.error) - var trades = trades.map(function (trade) { + var trades = body.filter(t => { + return (typeof opts.from === 'undefined') ? true : (moment.unix(t.date).valueOf() > opts.from) + }).reverse().map(function (trade) { return { trade_id: trade.tid, time: moment.unix(trade.date).valueOf(), - size: trade.amount, - price: trade.price, + size: Number(trade.amount), + price: Number(trade.price), side: trade.side } }) @@ -101,11 +104,11 @@ module.exports = function container (get, set, clear) { currency: 0 } - balance.currency = wallet[currency + '_balance'] - balance.asset = wallet[asset + '_balance'] + balance.currency = Number(wallet[currency + '_balance']); + balance.asset = Number(wallet[asset + '_balance']); - balance.currency_hold = wallet[currency + '_reserved'] - balance.asset_hold = wallet[asset + '_reserved'] + balance.currency_hold = Number(wallet[currency + '_reserved']) + balance.asset_hold = Number(wallet[asset + '_reserved']) cb(null, balance) }) }, @@ -123,8 +126,8 @@ module.exports = function container (get, set, clear) { if (quote.error) return retry('getQuote', func_args, quote.error) var r = { - bid: quote.bid, - ask: quote.ask + bid: Number(quote.bid), + ask: Number(quote.ask) } cb(null, r) @@ -160,15 +163,18 @@ module.exports = function container (get, set, clear) { var order = { id: null, status: 'open', - price: opts.price, - size: opts.size, + price: Number(opts.price), + size: Number(opts.size), created_at: new Date().getTime(), - filled_size: '0', + filled_size: 0, ordertype: opts.order_type } if (err) return cb(err) - if (body.error) return cb(body.error.message) + if (body.error) { + //console.log(`API Error: ${body.error.message}`); + return cb(body.error) + } if (opts.order_type === 'taker') { order.status = 'done' @@ -179,15 +185,15 @@ module.exports = function container (get, set, clear) { var price_total = 0.0 var order_count = body.orders_matched.length for (var idx = 0; idx < order_count; idx++) { - asset_total = asset_total + body.orders_matched[idx].amount - price_total = price_total + (body.orders_matched[idx].amount * body.orders_matched[idx].price) + asset_total = asset_total + Number(body.orders_matched[idx].amount) + price_total = price_total + (Number(body.orders_matched[idx].amount) * Number(body.orders_matched[idx].price)) } order.price = price_total / asset_total order.size = asset_total } else { - order.price = body.price - order.size = body.amount + order.price = Number(body.price) + order.size = Number(body.amount) } } @@ -212,15 +218,18 @@ module.exports = function container (get, set, clear) { var order = { id: null, status: 'open', - price: opts.price, - size: opts.size, + price: Number(opts.price), + size: Number(opts.size), created_at: new Date().getTime(), - filled_size: '0', + filled_size: 0, ordertype: opts.order_type } if (err) return cb(err) - if (body.error) return cb(body.error.message) + if (body.error) { + //console.log(`API Error: ${body.error.message}`); + return cb(body.error) + } if (opts.order_type === 'taker') { order.status = 'done' @@ -231,15 +240,15 @@ module.exports = function container (get, set, clear) { var price_total = 0.0 var order_count = body.orders_matched.length for (var idx = 0; idx < order_count; idx++) { - asset_total = asset_total + body.orders_matched[idx].amount - price_total = price_total + (body.orders_matched[idx].amount * body.orders_matched[idx].price) + asset_total = asset_total + Number(body.orders_matched[idx].amount) + price_total = price_total + (Number(body.orders_matched[idx].amount) * body.orders_matched[idx].price) } order.price = price_total / asset_total order.size = asset_total } else { - order.price = body.price - order.size = body.amount + order.price = Number(body.price) + order.size = Number(body.amount) } } @@ -258,12 +267,15 @@ module.exports = function container (get, set, clear) { var client = authedClient() client.api('lookup_order', params, function (err, body) { if (err) return cb(err) - if (body.error) return cb(body.error.message) + if (body.error) { + //console.log(`API Error: ${body.error.message}`); + return cb(body.error) + } if (body.status === 2) { order.status = 'done' order.done_at = new Date().getTime() - order.filled_size = body.amount + order.filled_size = Number(body.amount) return cb(null, order) } cb(null, order) diff --git a/extensions/exchanges/quadriga/package-lock.json b/extensions/exchanges/quadriga/package-lock.json new file mode 100644 index 0000000000..f8c19fee50 --- /dev/null +++ b/extensions/exchanges/quadriga/package-lock.json @@ -0,0 +1,396 @@ +{ + "name": "zenbot_quadrigacx", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "requires": { + "co": "4.6.0", + "json-stable-stringify": "1.0.1" + } + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=" + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "requires": { + "hoek": "2.16.3" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "requires": { + "delayed-stream": "1.0.0" + } + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "requires": { + "boom": "2.10.1" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + }, + "extsprintf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", + "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.16" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "har-schema": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", + "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=" + }, + "har-validator": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", + "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", + "requires": { + "ajv": "4.11.8", + "har-schema": "1.0.5" + } + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.0", + "sshpk": "1.13.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + }, + "jsprim": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz", + "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.0.2", + "json-schema": "0.2.3", + "verror": "1.3.6" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "mime-db": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.29.0.tgz", + "integrity": "sha1-SNJtI1WJZRcErFkWygYAGRQmaHg=" + }, + "mime-types": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.16.tgz", + "integrity": "sha1-K4WKUuXs1RbbiXrCvodIeDBpjiM=", + "requires": { + "mime-db": "1.29.0" + } + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + }, + "performance-now": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=" + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "qs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=" + }, + "quadrigacx": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/quadrigacx/-/quadrigacx-0.0.7.tgz", + "integrity": "sha1-vptrBG28vDpNqRbBpQtJ2kiulsQ=", + "requires": { + "request": "2.81.0" + } + }, + "request": { + "version": "2.81.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", + "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "4.2.1", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.16", + "oauth-sign": "0.8.2", + "performance-now": "0.2.0", + "qs": "6.4.0", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.2", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "requires": { + "hoek": "2.16.3" + } + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + } + } + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" + }, + "tough-cookie": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", + "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": true + }, + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" + }, + "verror": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", + "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", + "requires": { + "extsprintf": "1.0.2" + } + } + } +} diff --git a/extensions/exchanges/quadriga/products.json b/extensions/exchanges/quadriga/products.json index 298c236fa8..331a2d886d 100644 --- a/extensions/exchanges/quadriga/products.json +++ b/extensions/exchanges/quadriga/products.json @@ -1,5 +1,4 @@ -[ - { +[{ "id": "BTCUSD", "asset": "BTC", "currency": "USD", @@ -34,5 +33,14 @@ "max_size": "1000000", "increment": "0.00001", "label": "ETH/BTC" + }, + { + "id": "LTCCAD", + "asset": "LTC", + "currency": "CAD", + "min_size": "0.00001", + "max_size": "10000", + "increment": "0.00001", + "label": "LTC/CAD" } ] diff --git a/extensions/strategies/srsi_macd/strategy.js b/extensions/strategies/srsi_macd/strategy.js index 5e9ad5a998..b52bca6fda 100644 --- a/extensions/strategies/srsi_macd/strategy.js +++ b/extensions/strategies/srsi_macd/strategy.js @@ -3,7 +3,7 @@ let z = require('zero-fill'), module.exports = function container (get, set, clear) { return { - name: 'rsi_macd', + name: 'srsi_macd', description: 'Stochastic MACD Strategy', getOptions: function () { diff --git a/lib/engine.js b/lib/engine.js index f6efb9f7ba..c56657c784 100644 --- a/lib/engine.js +++ b/lib/engine.js @@ -290,7 +290,7 @@ module.exports = function container (get, set, clear) { cb(null, order) }) } - if (order.status === 'rejected' && order.reject_reason === 'post only') { + if (order.status === 'rejected' && (order.reject_reason === 'post only' || api_order.reject_reason === 'post only')) { msg('post-only ' + type + ' failed, re-ordering') return cancelOrder(true) } @@ -432,7 +432,7 @@ module.exports = function container (get, set, clear) { return cb(err) } } - if (n(s.balance.currency).subtract(s.balance.currency_hold || 0).value() < n(price).multiply(size).value()) { + if (n(s.balance.currency).subtract(s.balance.currency_hold || 0).value() < n(price).multiply(size).value() && s.balance.currency_hold > 0) { msg('buy delayed: ' + pct(n(s.balance.currency_hold || 0).divide(s.balance.currency).value()) + ' of funds (' + fc(s.balance.currency_hold) + ') on hold') return setTimeout(function () { if (s.last_signal === signal) { diff --git a/scripts/auto_backtester/backtester.js b/scripts/auto_backtester/backtester.js index feae1dc38e..5de0564870 100755 --- a/scripts/auto_backtester/backtester.js +++ b/scripts/auto_backtester/backtester.js @@ -62,12 +62,12 @@ const objectProduct = obj => { const keys = Object.keys(obj) const values = keys.map(function (x) { return obj[x] }) - return product(values).map(function (p) { - const e = {} - keys.forEach(function (k, n) { e[k] = p[n] }) - return e - }) -} + return product(values).map(function(p) { + var e = {}; + keys.forEach(function(k, n) { e[k] = p[n] }); + return e; + }); +}; const processOutput = output => { const jsonRegexp = /(\{[\s\S]*?\})\send balance/g diff --git a/zenbot.bat b/zenbot.bat new file mode 100644 index 0000000000..990a084240 --- /dev/null +++ b/zenbot.bat @@ -0,0 +1 @@ +node zenbot.sh %* \ No newline at end of file