From 9594761d1a65be2204bfd7e45235808c39107ecd Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 14 Jul 2016 12:58:14 -0700 Subject: [PATCH 01/56] overhaul --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 5106b917d2..f0bf51e571 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,10 @@ > “To follow the path, look to the master, follow the master, walk with the master, see through the master, become the master.” > – Zen Proverb +## Overhaul in progress! + +zenbot is now undergoing a large [overhaul (3.x)](https://github.com/carlos8f/zenbot/tree/3.x) which will add multi-exchange support. The current 2.x version should be considered a working proof of concept. Please be patient until 3.x lands! + ## Screenshot ![screenshot](https://cloud.githubusercontent.com/assets/106763/16441892/e791744c-3d82-11e6-834e-b566d498e7e9.png) From 796dec1922ff23ad049826c2d5322cdc4a2cc441 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 14 Aug 2016 12:18:02 -0700 Subject: [PATCH 02/56] fix user agent const --- bin/zenbot | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/zenbot b/bin/zenbot index 92c5477da0..f4e74fa178 100755 --- a/bin/zenbot +++ b/bin/zenbot @@ -1,6 +1,6 @@ #!/usr/bin/env node var version = require('../package.json').version -ZENBOT_USER_AGENT = 'zenbot/' + version +ZENBOT_USER_AGENT = USER_AGENT = 'zenbot/' + version var constants = require('../conf/constants.json') var launch = require('../utils/launch') From b41357385c07be4f970e42d2b5b11bddbfd62cd3 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 14 Aug 2016 13:35:35 -0700 Subject: [PATCH 03/56] 3.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 79ba502423..8a5a0697ea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zenbot_trader", - "version": "2.8.10", + "version": "3.0.0", "description": "A machine-learning cryptocurrency trading bot", "bin": { "zenbot": "./zenbot" From fa4b923297edd00dec4ff5d887d48afec4572bee Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 14 Aug 2016 13:36:56 -0700 Subject: [PATCH 04/56] fix images --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 279d1b5350..0f6c1eca13 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ HOWEVER. BE AWARE that once you hook up zenbot to a live exchange, the damage do ## Screenshot -![screenshot](https://rawgit.com/carlos8f/zenbot/master/assets/zenbot_web_ui.png) +![screenshot](https://raw.githubusercontent.com/carlos8f/zenbot/master/assets/zenbot_web_ui.png) ## Quick-start @@ -82,7 +82,7 @@ Zenbot will return you a list of virtual trades, and an ROI figure. Open the URL When the server is running, and you have visited the `?secret` URL provided in the console, you can access an aggregated, live feed of log messages at `http://localhost:3013/logs`. Example: -![screenshot](https://rawgit.com/carlos8f/zenbot/master/assets/zenbot_web_logs.png) +![screenshot](https://raw.githubusercontent.com/carlos8f/zenbot/master/assets/zenbot_web_logs.png) ## FAQ From fe4de54a401e4679ee6a41537dfe190bdd95d4c9 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 14 Aug 2016 13:41:17 -0700 Subject: [PATCH 05/56] fix script branch --- install.sh | 2 -- update.sh | 1 - 2 files changed, 3 deletions(-) diff --git a/install.sh b/install.sh index eeaa62538c..5b56b16c47 100755 --- a/install.sh +++ b/install.sh @@ -1,9 +1,7 @@ #!/bin/bash git clone https://github.com/carlos8f/zenbot.git cd zenbot -git checkout 3.x git pull npm install -npm install zenbrain sudo rm -Rf /usr/local/bin/zenbot sudo npm link diff --git a/update.sh b/update.sh index 620011f958..1e3fbceade 100755 --- a/update.sh +++ b/update.sh @@ -1,5 +1,4 @@ #!/bin/bash -git checkout 3.x git pull npm install npm install zenbrain From 807dcf4110e8f8e5e8481ed82968b34d9b2322fd Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 14 Aug 2016 13:51:11 -0700 Subject: [PATCH 06/56] fix --- README.md | 2 ++ plugins/server/controllers/data.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0f6c1eca13..1480f0d40f 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,8 @@ HOWEVER. BE AWARE that once you hook up zenbot to a live exchange, the damage do ### 2. Install zenbot 3: +Note: it will ask for your password. This is for `sudo rm -Rf /usr/local/bin/zenbot && sudo npm link` to install the binary. + ```shell curl --silent https://raw.githubusercontent.com/carlos8f/zenbot/master/install.sh | /bin/sh ``` diff --git a/plugins/server/controllers/data.js b/plugins/server/controllers/data.js index adf9f3dfc8..5a2c38f305 100644 --- a/plugins/server/controllers/data.js +++ b/plugins/server/controllers/data.js @@ -44,7 +44,7 @@ module.exports = function container (get, set) { if (!run_state) return res.renderStatus(404) res.setHeader('Content-Type', 'text/csv') res.write('Type,Time,Asset,Currency,Exchange,Price,Size,RSI,ROI\n') - run_state.actions.forEach(function (action) { + (run_state.actions || []).forEach(function (action) { var line = [ action.type, action.time, From 74c7c3048a5e0bc53da711ca08d382d1cca0f212 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 14 Aug 2016 13:55:35 -0700 Subject: [PATCH 07/56] delete install script --- README.md | 8 ++++---- install.sh | 7 ------- 2 files changed, 4 insertions(+), 11 deletions(-) delete mode 100755 install.sh diff --git a/README.md b/README.md index 1480f0d40f..31eb7f4aaf 100644 --- a/README.md +++ b/README.md @@ -30,13 +30,13 @@ HOWEVER. BE AWARE that once you hook up zenbot to a live exchange, the damage do ### 2. Install zenbot 3: -Note: it will ask for your password. This is for `sudo rm -Rf /usr/local/bin/zenbot && sudo npm link` to install the binary. - ```shell -curl --silent https://raw.githubusercontent.com/carlos8f/zenbot/master/install.sh | /bin/sh +git clone https://github.com/carlos8f/zenbot.git +cd zenbot +npm install ``` -### 3. Edit `zenbot/config.js` with API keys, database credentials, trade logic, etc. +### 3. Edit `config.js` with API keys, database credentials, trade logic, etc. ### 4. Run zenbot on the exchange: diff --git a/install.sh b/install.sh deleted file mode 100755 index 5b56b16c47..0000000000 --- a/install.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -git clone https://github.com/carlos8f/zenbot.git -cd zenbot -git pull -npm install -sudo rm -Rf /usr/local/bin/zenbot -sudo npm link From f3f330c9468de290942cf90c1df9e032e07a792a Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 14 Aug 2016 14:03:41 -0700 Subject: [PATCH 08/56] 3.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8a5a0697ea..831b2eb3e0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zenbot_trader", - "version": "3.0.0", + "version": "3.0.1", "description": "A machine-learning cryptocurrency trading bot", "bin": { "zenbot": "./zenbot" From a2322115654003ace8dee4af73e67e5c0b21bf9f Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 14 Aug 2016 14:04:40 -0700 Subject: [PATCH 09/56] report 1m --- config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.js b/config.js index ede12e4aad..249a387982 100644 --- a/config.js +++ b/config.js @@ -239,7 +239,7 @@ c.logic = function container (get, set, clear) { // END DEFAULT TRADE LOGIC ] } -c.reporter_sizes = ['15m'] +c.reporter_sizes = ['1m', '15m'] c.price_reporter_selector = "gdax.BTC-USD" c.price_reporter_length = 9 c.reporter_cols = [ From f6047199eddb1ffd865959304b3b2c67f54d33ed Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 14 Aug 2016 14:05:31 -0700 Subject: [PATCH 10/56] fix run --- run.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.sh b/run.sh index 59de097cbd..8df0de188f 100755 --- a/run.sh +++ b/run.sh @@ -1,2 +1,2 @@ #!/bin/bash -zenbot launch map --backfill reduce run server +./zenbot launch map --backfill reduce run server From 9ee7b2692e3401412180b8c34ed3dc024187e473 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 14 Aug 2016 14:06:43 -0700 Subject: [PATCH 11/56] fix data csv --- plugins/server/controllers/data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/server/controllers/data.js b/plugins/server/controllers/data.js index 5a2c38f305..d47aa58427 100644 --- a/plugins/server/controllers/data.js +++ b/plugins/server/controllers/data.js @@ -44,7 +44,7 @@ module.exports = function container (get, set) { if (!run_state) return res.renderStatus(404) res.setHeader('Content-Type', 'text/csv') res.write('Type,Time,Asset,Currency,Exchange,Price,Size,RSI,ROI\n') - (run_state.actions || []).forEach(function (action) { + ;(run_state.actions || []).forEach(function (action) { var line = [ action.type, action.time, From f5cb886a8505929c95e61a3e3af78b47d62aec85 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 14 Aug 2016 14:07:38 -0700 Subject: [PATCH 12/56] 3.0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 831b2eb3e0..d4f55f5822 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zenbot_trader", - "version": "3.0.1", + "version": "3.0.2", "description": "A machine-learning cryptocurrency trading bot", "bin": { "zenbot": "./zenbot" From fe8e027dfd923b5a3757cfd8666701cf4d3a1fbb Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 14 Aug 2016 15:04:56 -0700 Subject: [PATCH 13/56] expand --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 31eb7f4aaf..e78a439435 100644 --- a/README.md +++ b/README.md @@ -86,6 +86,19 @@ When the server is running, and you have visited the `?secret` URL provided in t ![screenshot](https://raw.githubusercontent.com/carlos8f/zenbot/master/assets/zenbot_web_logs.png) +## About the default trade logic in config.js + +- uses [GDAX](https://gdax.com/) API +- watches/trades BTC/USD +- acts at 15m increments (ticks) +- computes 14-period 15m RSI +- considers `RSI > 70` overbought and `RSI < 30` oversold +- trades 95% of current balance, market price + +You can tweak `config.js` from there to use bitfinex, or trade ETH, or whatever. Common `config.js` logic will be moved to core or plugins in later versions of zenbot. Use `zenbot sim` to check your trade strategy against historical trades. + +Auto-learn support and more exchange support will come soon. Will accept PR's :) With the 3.x plugin architecture, external plugins are possible too (published as their own repo/module). + ## FAQ ### Can I use zenbot with [X] exchange? From 1061f65ff7920e526939a3d24e46fbfa89b19087 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 14 Aug 2016 15:17:10 -0700 Subject: [PATCH 14/56] fix data controller err --- plugins/server/controllers/data.js | 37 +++++++++++++++--------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/plugins/server/controllers/data.js b/plugins/server/controllers/data.js index d47aa58427..de3eaa213d 100644 --- a/plugins/server/controllers/data.js +++ b/plugins/server/controllers/data.js @@ -7,28 +7,29 @@ module.exports = function container (get, set) { var format_currency = get('zenbrain:utils.format_currency') return get('controller')() .get('/sim_trades.csv', function (req, res, next) { - if (!req.query.sim_id) { - return next(new Error('sim_id required')) - } res.setHeader('Content-Type', 'text/csv') res.write('Type,Time,Asset,Currency,Exchange,Price,Size,RSI,ROI\n') + if (!req.session.secret) { + return res.end() + } get('db.run_states').load(req.query.sim_id, function (err, sim_result) { if (err) return next(err) - if (!sim_result) return res.renderStatus(404) - sim_result.actions.forEach(function (action) { - var line = [ - action.type, - action.time, - action.asset, - action.currency, - action.exchange, - action.price, - action.size, - action.rsi, - action.roi - ].join(',') - res.write(line + '\n') - }) + if (sim_result && sim_result.actions) { + sim_result.actions.forEach(function (action) { + var line = [ + action.type, + action.time, + action.asset, + action.currency, + action.exchange, + action.price, + action.size, + action.rsi, + action.roi + ].join(',') + res.write(line + '\n') + }) + } res.end() }) }) From dde9521fd802fb067d0c5450cb284dbde254b5d1 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 14 Aug 2016 15:19:30 -0700 Subject: [PATCH 15/56] 3.0.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d4f55f5822..1cb63075d8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zenbot_trader", - "version": "3.0.2", + "version": "3.0.3", "description": "A machine-learning cryptocurrency trading bot", "bin": { "zenbot": "./zenbot" From e974f2af4de73fd6398e5a77af26d42a665bec7f Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 14 Aug 2016 15:38:28 -0700 Subject: [PATCH 16/56] fix --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e78a439435..cc37de194b 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,10 @@ zenbot is an automated cryptocurrency trading bot. It runs on node.js and MongoDB and is fully open-sourced. A plugin architecture is included that allows any exchange, trade strategy, or currency pair to be supported. -- Out of the box, zenbot is an AI-powered trade advisor for GDAX (gives you buy or sell signals while watching live data). -- Enable trades by simply giving it your GDAX API key. -- Trade strategy is exposed in the config file. This allows you to have full control over the bot's actions and logic. For example, instead of trading on GDAX, you could trade on a different exchange or currency pair by implementing a few lines of JavaScript. +- Out of the box, zenbot is an AI-powered trade advisor (gives you buy or sell signals while watching live data). +- Default support for [GDAX](https://gdax.com/) is included, so if you have a GDAX account, enable bot trades by simply putting your GDAX API key in `config.js` and setting what currency pair to trade. +- Default support for other exchanges is ongoing. +- Trade strategy is fully exposed in the config file. This allows you to have full control over the bot's actions and logic. For example, instead of trading on GDAX, you could trade on a different exchange or currency pair by implementing a few lines of JavaScript. - A live candlestick graph is provided via a built-in HTTP server. HOWEVER. BE AWARE that once you hook up zenbot to a live exchange, the damage done is your fault, not mine! **As with buying bitcoin in general, risk is involved and caution is essential. bitcoin is an experiment, and so is zenbot.** From 32b3a8363c8ed8ec2591eb23c216c538a5c0d0e7 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 14 Aug 2016 16:05:01 -0700 Subject: [PATCH 17/56] btc --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index cc37de194b..becfd55beb 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,10 @@ While the advanced mathematical nature of such adaptive systems has kept neural Source: [Wikipedia](https://en.wikipedia.org/wiki/Technical_analysis#Systematic_trading) +## Donate + +P.S., some have asked for how to donate to Zenbot development. I accept donations at [my Bitcoin address](bitcoin:187rmNSkSvehgcKpBunre6a5wA5hQQop6W), thanks! + - - - ### License: MIT From 4850601c833db26e24a4669d2e3a573bb726067c Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 14 Aug 2016 16:33:23 -0700 Subject: [PATCH 18/56] discuss --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index becfd55beb..78e512b4dc 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ - Follow zenbot [on Twitter!](https://twitter.com/zenbot_btc) - Check out zenbot's [live feed!](https://zenbot.s8f.org/) -- Join the discussion on [Reddit!](https://www.reddit.com/r/Bitcoin/comments/4rym6o/zenbot_an_automated_bitcoin_trading_bot_for_gdax/) +- Join the discussion on [Reddit!](https://www.reddit.com/r/Bitcoin/comments/4xqo8q/announcing_zenbot_3_your_new_btcethltc_trading/)! ## Description @@ -136,6 +136,9 @@ Source: [Wikipedia](https://en.wikipedia.org/wiki/Technical_analysis#Systematic_ P.S., some have asked for how to donate to Zenbot development. I accept donations at [my Bitcoin address](bitcoin:187rmNSkSvehgcKpBunre6a5wA5hQQop6W), thanks! +## Discuss + +Join the [discussion on Reddit](https://www.reddit.com/r/Bitcoin/comments/4xqo8q/announcing_zenbot_3_your_new_btcethltc_trading/)! - - - ### License: MIT From 8c18845a9b6bdf2e5269385f0857d14bdb05e2bd Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 14 Aug 2016 18:11:53 -0700 Subject: [PATCH 19/56] default trade logic, 6h RSI --- README.md | 4 ++-- config.js | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 78e512b4dc..c12a70a4c6 100644 --- a/README.md +++ b/README.md @@ -91,8 +91,8 @@ When the server is running, and you have visited the `?secret` URL provided in t - uses [GDAX](https://gdax.com/) API - watches/trades BTC/USD -- acts at 15m increments (ticks) -- computes 14-period 15m RSI +- acts at 6h increments (ticks), but you can configure to act quicker or slower. +- computes 14-period 6h RSI - considers `RSI > 70` overbought and `RSI < 30` oversold - trades 95% of current balance, market price diff --git a/config.js b/config.js index 249a387982..67b7d4f8fe 100644 --- a/config.js +++ b/config.js @@ -55,7 +55,7 @@ c.graph_selectors = [ c.rsi_query_limit = 100 c.rsi_periods = 14 c.rsi_reporter_selector = "gdax.BTC-USD" -c.rsi_sizes = ['15m', '1h'] +c.rsi_sizes = ['15m', '1h', '6h'] c.key = '' // TO ENABLE BOT TRADING: set this to GDAX api key, c.secret = '' // set this to GDAX api secret, c.passphrase = '' // set this to GDAX api passphrase. @@ -71,7 +71,7 @@ c.logic = function container (get, set, clear) { var client = new CoinbaseExchange.AuthenticatedClient(c.key, c.secret, c.passphrase) var asset = 'BTC' var currency = 'USD' - var rsi_period = '15m' + var rsi_period = '6h' var exchange = 'gdax' var selector = 'data.trades.' + exchange + '.' + asset + '-' + currency function onOrder (err, resp, order) { @@ -239,7 +239,7 @@ c.logic = function container (get, set, clear) { // END DEFAULT TRADE LOGIC ] } -c.reporter_sizes = ['1m', '15m'] +c.reporter_sizes = ['1m', '15m', '1h', '6h'] c.price_reporter_selector = "gdax.BTC-USD" c.price_reporter_length = 9 c.reporter_cols = [ From 704ddf3112cf9b225cb2b0bcc0014ba94ab5ca9e Mon Sep 17 00:00:00 2001 From: RDash Date: Mon, 15 Aug 2016 18:53:56 +0200 Subject: [PATCH 20/56] Added a few currencies for poloniex... <3 --- .gitignore | 1 + config.js | 262 ----- plugins/poloniex/exchange.json | 1239 +++++++++++++++++++++- sample-config.js | 1767 ++++++++++++++++++++++++++++++++ 4 files changed, 3001 insertions(+), 268 deletions(-) delete mode 100644 config.js create mode 100644 sample-config.js diff --git a/.gitignore b/.gitignore index 11399b5391..0a07bfe046 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ npm-debug.log db.json dump conf/secret.json +config.json diff --git a/config.js b/config.js deleted file mode 100644 index 67b7d4f8fe..0000000000 --- a/config.js +++ /dev/null @@ -1,262 +0,0 @@ -var c = module.exports = {} -c.mongo_url = "mongodb://localhost:27017/zenbrain" // change if your mongo server isn't local -c.mongo_username = null // normally not needed -c.mongo_password = null -c.bucket_size = "1m" -c.reducer_limit = 500 // how many thoughts to process per reduce run -c.reducer_sizes = ["1m", "5m", "15m", "1h", "6h", "1d"] -c.save_state_interval = 10000 // save state -c.parallel_limit = 8 // run this many concurrent tasks -c.reduce_timeout = 200 -c.run_limit = 100 -c.lock_timeout = 60000 -c.lock_backoff = 20 -c.lock_tries = 100 -c.passive_update_timeout = 5000 -c.return_timeout = 60000 -c.brain_speed_ms = 200 -c.twitter_key = "" // create a twitter app, generate an access token, and add it here -c.twitter_secret = "" -c.twitter_access_token = "" -c.twitter_access_token_secret = "" -c.assets = [ - "BTC", - //"ETH", - //"LTC" -] -c.currencies = [ - //"CNY", - //"EUR", - "USD" -] -c.enabled_plugins = [ - //"bitfinex", - "gdax", - //"poloniex", - "server" -] -c.default_graph_period = "1h" -c.default_graph_limit = 300 -c.graph_limits = [50, 100, 150, 200, 300, 500, 1000, 2000] -c.graph_selectors = [ - "gdax.BTC-USD", - //"gdax.BTC-EUR", - //"gdax.ETH-USD", - //"poloniex.BTC-USD", - //"bitfinex.BTC-USD", - //"bitfinex.ETH-USD", - //"bitfinex.ETH-BTC", - //"bitfinex.ETC-BTC", - //"bitfinex.LTC-USD", - //"bitfinex.LTC-BTC", - //"bitfinex.ETC-BTC", - //"bitfinex.ETC-USD" -] -c.rsi_query_limit = 100 -c.rsi_periods = 14 -c.rsi_reporter_selector = "gdax.BTC-USD" -c.rsi_sizes = ['15m', '1h', '6h'] -c.key = '' // TO ENABLE BOT TRADING: set this to GDAX api key, -c.secret = '' // set this to GDAX api secret, -c.passphrase = '' // set this to GDAX api passphrase. -var first_run = true -var last_balance_sig -c.logic = function container (get, set, clear) { - var o = get('utils.object_get') - var n = require('numbro') - var sig = require('sig') - var format_currency = get('utils.format_currency') - var get_timestamp = get('utils.get_timestamp') - var CoinbaseExchange = require('coinbase-exchange') - var client = new CoinbaseExchange.AuthenticatedClient(c.key, c.secret, c.passphrase) - var asset = 'BTC' - var currency = 'USD' - var rsi_period = '6h' - var exchange = 'gdax' - var selector = 'data.trades.' + exchange + '.' + asset + '-' + currency - function onOrder (err, resp, order) { - if (err) return get('logger').error('order err', err, resp, order, {feed: 'errors'}) - if (resp.statusCode !== 200) { - console.error(order) - return get('logger').error('non-200 status: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: order}}) - } - get('logger').info(exchange, ('order-id: ' + order.id).cyan, {data: {order: order}}) - function getStatus () { - client.getOrder(order.id, function (err, resp, order) { - if (err) return get('logger').error('getOrder err', err) - if (resp.statusCode !== 200) { - console.error(order) - return get('logger').error('non-200 status from getOrder: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: order}}) - } - if (order.status === 'done') { - return get('logger').info(exchange, ('order ' + order.id + ' done: ' + order.done_reason).cyan, {data: {order: order}}) - } - else { - get('logger').info(exchange, ('order ' + order.id + ' ' + order.status).cyan, {data: {order: order}}) - setTimeout(getStatus, 5000) - } - }) - } - getStatus() - } - return [ - // BEGIN DEFAULT TRADE LOGIC - // sync balance - function (tick, trigger, rs, cb) { - if (get('command') !== 'run' || !c.key) { - return cb() - } - client.getAccounts(function (err, resp, accounts) { - if (err) throw err - if (resp.statusCode !== 200) { - console.error(accounts) - get('logger').error('non-200 status from exchange: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: accounts}}) - return cb && cb() - } - rs.balance = {} - accounts.forEach(function (account) { - if (account.currency === currency) { - rs.balance[currency] = n(account.balance).value() - } - else if (account.currency === asset) { - rs.balance[asset] = n(account.balance).value() - } - }) - var balance_sig = sig(rs.balance) - if (balance_sig !== last_balance_sig) { - get('logger').info(exchange, 'balance'.grey, n(rs.balance[asset]).format('0.000').white, asset.grey, n(rs.balance[currency]).format('0.00').yellow, currency.grey, {feed: 'exchange'}) - first_run = false - last_balance_sig = balance_sig - } - cb && cb() - }) - }, - function (tick, trigger, rs, cb) { - // note the last close price - var market_price = o(tick, selector + '.close') - if (market_price) { - rs.market_price = market_price - } - if (!rs.market_price) return cb() - if (!rs.balance) { - // start with $1000, neutral position - rs.balance = {} - rs.balance[currency] = 500 - rs.balance[asset] = n(500).divide(rs.market_price).value() - } - rs.ticks || (rs.ticks = 0) - rs.ticks++ - if (tick.size !== rsi_period) return cb() - // get rsi - var rsi = o(tick, selector + '.rsi') - // require minimum data - // overbought/oversold - // sanity check - if (rsi && rsi.samples >= c.rsi_periods) { - rs.rsi = Math.round(rsi.value) - rs.rsi_ansi = rsi.ansi - if (rsi.value > 70) { - rs.overbought = true - rs.oversold = false - } - else if (rsi.value < 30) { - rs.oversold = true - rs.overbought = false - } - } - cb() - }, - // @todo MACD - function (tick, trigger, rs, cb) { - cb() - }, - // trigger trade signals - function (tick, trigger, rs, cb) { - if ((rs.overbought || rs.oversold) && rs.balance && rs.market_price) { - var size, new_balance = {} - if (rs.overbought) { - get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, 'anticipating a reversal DOWN. sell at market. (' + format_currency(rs.market_price, currency) + ')', {feed: 'trader'}) - size = rs.balance[asset] - } - else if (rs.oversold) { - get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, 'anticipating a reversal UP. buy at market. (' + format_currency(rs.market_price, currency) + ')', {feed: 'trader'}) - size = n(rs.balance[currency]).divide(rs.market_price).value() - } - // scale down size a little, to prevent out-of-balance errors - size = n(size || 0).multiply(0.95).value() - // min size - if (!size || size < 0.01) { - if (rs.overbought) { - get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, ('not enough ' + asset + ' to execute sell!').red, {feed: 'trader'}) - } - else if (rs.oversold) { - get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, ('not enough ' + currency + ' to execute buy!').red, {feed: 'trader'}) - } - rs.overbought = rs.oversold = false - return cb() - } - if (rs.overbought) { - new_balance[currency] = n(rs.balance[currency]).add(n(size).multiply(rs.market_price)).value() - new_balance[asset] = n(rs.balance[asset]).subtract(size).value() - } - else if (rs.oversold) { - new_balance[asset] = n(rs.balance[asset]).add(size).value() - new_balance[currency] = n(rs.balance[currency]).subtract(n(size).multiply(rs.market_price)).value() - } - // consolidate balance - var new_end_balance = n(new_balance[currency]).add(n(new_balance[asset]).multiply(rs.market_price)).value() - var new_roi = n(new_end_balance).divide(1000).value() - rs.balance = new_balance - rs.end_balance = new_end_balance - rs.roi = new_roi - rs.trades || (rs.trades = 0) - rs.trades++ - trigger({ - type: rs.overbought ? 'sell' : 'buy', - asset: asset, - currency: currency, - exchange: exchange, - price: rs.market_price, - market: true, - size: size, - rsi: rs.rsi, - roi: rs.roi - }) - if (get('command') === 'run' && c.key) { - var params = { - type: 'market', - size: n(size).format('0.000000'), - product_id: asset + '-' + currency - } - client[rs.overbought ? 'sell' : 'buy'](params, function (err, resp, order) { - onOrder(err, resp, order) - }) - } - rs.overbought = rs.oversold = false - } - cb() - } - // END DEFAULT TRADE LOGIC - ] -} -c.reporter_sizes = ['1m', '15m', '1h', '6h'] -c.price_reporter_selector = "gdax.BTC-USD" -c.price_reporter_length = 9 -c.reporter_cols = [ - "tick_id", - "num_trades", - "timestamp", - "rsi", - "volume", - "price" -] -c.backfill_days = 91 -c.record_timeout = 20000 -c.backfill_timeout = 5000 -c.reducer_report_interval = 2000 -c.trade_report_interval = 10000 -c.sim_input_unit = "7d" -c.sim_input_limit = 12 -c.log_query_limit = 200 -c.tracking_scripts = '' - diff --git a/plugins/poloniex/exchange.json b/plugins/poloniex/exchange.json index 48fe095738..97fcc4b491 100644 --- a/plugins/poloniex/exchange.json +++ b/plugins/poloniex/exchange.json @@ -3,13 +3,1240 @@ "rest_url": "https://poloniex.com/public", "products": [ { - "id":"USDT_BTC", + "id":"BTC_1CR", "asset":"BTC", - "currency":"USD", - "min_size":0.01, + "currency":"1CR", + "min_size":0.0001, "max_size":10000, "increment":0.01, - "label":"USDT/BTC" - } + "label":"BTC/1CR" + }, + { + "id":"BTC_ABY", + "asset":"BTC", + "currency":"ABY", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/1CR" + }, + { + "id":"BTC_AC", + "asset":"BTC", + "currency":"AC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/1CR" + }, + { + "id":"BTC_ACH", + "asset":"BTC", + "currency":"ACH", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/1CR" + }, + { + "id":"BTC_ADN", + "asset":"BTC", + "currency":"ADN", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/ADN" + }, + { + "id":"BTC_AEON", + "asset":"BTC", + "currency":"AEON", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/1CR" + }, + { + "id":"BTC_AERO", + "asset":"BTC", + "currency":"AERO", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/AERO" + }, + { + "id":"BTC_AIR", + "asset":"BTC", + "currency":"AIR", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/AIR" + }, + { + "id":"BTC_AMP", + "asset":"BTC", + "currency":"AMP", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/AMP" + }, + { + "id":"BTC_APH", + "asset":"BTC", + "currency":"APH", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/APH" + }, + { + "id":"BTC_ARCH", + "asset":"BTC", + "currency":"ARCH", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/ARCH" + }, + { + "id":"BTC_AUR", + "asset":"BTC", + "currency":"AUR", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/AUR" + }, + { + "id":"BTC_AXIS", + "asset":"BTC", + "currency":"AXIS", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/AXIS" + }, + { + "id":"BTC_BALLS", + "asset":"BTC", + "currency":"BALLS", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BALLS" + }, + { + "id":"BTC_BANK", + "asset":"BTC", + "currency":"BANK", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BANK" + }, + { + "id":"BTC_BBL", + "asset":"BTC", + "currency":"BBL", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BBL" + }, + { + "id":"BTC_BBR", + "asset":"BTC", + "currency":"BBR", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BBR" + }, + { + "id":"BTC_BCC", + "asset":"BTC", + "currency":"BCC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BCC" + }, + { + "id":"BTC_BCN", + "asset":"BTC", + "currency":"BCN", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BCN" + }, + { + "id":"BTC_BCY", + "asset":"BTC", + "currency":"BCY", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BCY" + }, + { + "id":"BTC_BDC", + "asset":"BTC", + "currency":"BDC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BDC" + }, + { + "id":"BTC_BDG", + "asset":"BTC", + "currency":"BDG", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BDG" + }, + { + "id":"BTC_BELA", + "asset":"BTC", + "currency":"BELA", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BELA" + }, + { + "id":"BTC_BITCNY", + "asset":"BTC", + "currency":"BITCNY", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BITCNY" + }, + { + "id":"BTC_BITS", + "asset":"BTC", + "currency":"BITS", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BITS" + }, + { + "id":"BTC_BITUSD", + "asset":"BTC", + "currency":"BITUSD", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BITUSD" + }, + + { + "id":"BTC_BLK", + "asset":"BTC", + "currency":"BLK", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BLK" + }, + + { + "id":"BTC_BLOCK", + "asset":"BTC", + "currency":"BLOCK", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BLOCK" + }, + + { + "id":"BTC_BLU", + "asset":"BTC", + "currency":"BLU", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BLU" + }, + { + "id":"BTC_BNS", + "asset":"BTC", + "currency":"BNS", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BNS" + }, + { + "id":"BTC_BONES", + "asset":"BTC", + "currency":"BONES", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BONES" + }, + { + "id":"BTC_BOST", + "asset":"BTC", + "currency":"BOST", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BOST" + }, + { + "id":"BTC_BTCD", + "asset":"BTC", + "currency":"BTCD", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BTCD" + }, + { + "id":"BTC_BTCS", + "asset":"BTC", + "currency":"BTCS", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BTCS" + }, + { + "id":"BTC_BTM", + "asset":"BTC", + "currency":"BTM", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BTM" + }, + { + "id":"BTC_BTS", + "asset":"BTC", + "currency":"BTS", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BTM" + }, + { + "id":"BTC_BURN", + "asset":"BTC", + "currency":"BURN", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BURN" + }, + { + "id":"BTC_BURST", + "asset":"BTC", + "currency":"BURST", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/BURST" + }, + { + "id":"BTC_C2", + "asset":"BTC", + "currency":"C2", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/C2" + }, + { + "id":"BTC_CACH", + "asset":"BTC", + "currency":"CACH", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/CACH" + }, + { + "id":"BTC_CAI", + "asset":"BTC", + "currency":"CAI", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/CAI" + }, + { + "id":"BTC_CC", + "asset":"BTC", + "currency":"CC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/CC" + }, + { + "id":"BTC_CCN", + "asset":"BTC", + "currency":"CCN", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/CCN" + }, + { + "id":"BTC_CGA", + "asset":"BTC", + "currency":"CGA", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/CGA" + }, + { + "id":"BTC_CHA", + "asset":"BTC", + "currency":"CHA", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/CHA" + }, + { + "id":"BTC_CINNI", + "asset":"BTC", + "currency":"CINNI", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/CINNI" + }, + { + "id":"BTC_CLAM", + "asset":"BTC", + "currency":"CLAM", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/CLAM" + }, + { + "id":"BTC_CNL", + "asset":"BTC", + "currency":"CNL", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/CNL" + }, + { + "id":"BTC_CNMT", + "asset":"BTC", + "currency":"CNMT", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/CNMT" + }, + { + "id":"BTC_CNOTE", + "asset":"BTC", + "currency":"CNOTE", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/CNOTE" + }, + { + "id":"BTC_COMM", + "asset":"BTC", + "currency":"COMM", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/COMM" + }, + { + "id":"BTC_CON", + "asset":"BTC", + "currency":"CON", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/CON" + }, + { + "id":"BTC_CORG", + "asset":"BTC", + "currency":"CORG", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/CORG" + }, + { + "id":"BTC_CRYPT", + "asset":"BTC", + "currency":"CRYPT", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/CRYPT" + }, + { + "id":"BTC_CURE", + "asset":"BTC", + "currency":"CURE", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/CURE" + }, + { + "id":"BTC_CYC", + "asset":"BTC", + "currency":"CYC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/CYC" + }, + { + "id":"BTC_DAO", + "asset":"BTC", + "currency":"DAO", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/DAO" + }, + { + "id":"BTC_DASH", + "asset":"BTC", + "currency":"DASH", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/DASH" + }, + { + "id":"BTC_DCR", + "asset":"BTC", + "currency":"DCR", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/DCR" + }, + { + "id":"BTC_DGB", + "asset":"BTC", + "currency":"DGB", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/DGB" + }, + { + "id":"BTC_DICE", + "asset":"BTC", + "currency":"DICE", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/DICE" + }, + { + "id":"BTC_DIEM", + "asset":"BTC", + "currency":"DIEM", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/DIEM" + }, + { + "id":"BTC_DIME", + "asset":"BTC", + "currency":"DIME", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/DIME" + }, + { + "id":"BTC_DIS", + "asset":"BTC", + "currency":"DIS", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/DIS" + }, + { + "id":"BTC_DNS", + "asset":"BTC", + "currency":"DNS", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/DNS" + }, + { + "id":"BTC_DOGE", + "asset":"BTC", + "currency":"DOGE", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/DOGE" + }, + { + "id":"BTC_DRKC", + "asset":"BTC", + "currency":"DRKC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/DRKC" + }, + { + "id":"BTC_DRM", + "asset":"BTC", + "currency":"DRM", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/DRM" + }, + { + "id":"BTC_DSH", + "asset":"BTC", + "currency":"DSH", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/DSH" + }, + { + "id":"BTC_DVK", + "asset":"BTC", + "currency":"DVK", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/DVK" + }, + { + "id":"BTC_EAC", + "asset":"BTC", + "currency":"EAC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/EAC" + }, + { + "id":"BTC_EBT", + "asset":"BTC", + "currency":"EBT", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/EBT" + }, + { + "id":"BTC_ECC", + "asset":"BTC", + "currency":"ECC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/ECC" + }, + { + "id":"BTC_EFL", + "asset":"BTC", + "currency":"EFL", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/EFL" + }, + { + "id":"BTC_EMC2", + "asset":"BTC", + "currency":"EMC2", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/EMC2" + }, + { + "id":"BTC_EMO", + "asset":"BTC", + "currency":"EMO", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/EMO" + }, + { + "id":"BTC_ENC", + "asset":"BTC", + "currency":"ENC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/ENC" + }, + { + "id":"BTC_ETC", + "asset":"BTC", + "currency":"ETC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/ETC" + }, + { + "id":"BTC_ETC", + "asset":"BTC", + "currency":"ETC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/ETC" + }, + { + "id":"BTC_ETC", + "asset":"BTC", + "currency":"ETC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/ETC" + }, + { + "id":"BTC_ETH", + "asset":"BTC", + "currency":"ETH", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/ETH" + }, + { + "id":"BTC_eTOK", + "asset":"BTC", + "currency":"eTOK", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/eTOK" + }, + { + "id":"BTC_EXE", + "asset":"BTC", + "currency":"EXE", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/EXE" + }, + { + "id":"BTC_EXP", + "asset":"BTC", + "currency":"EXP", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/EXP" + }, + { + "id":"BTC_FAC", + "asset":"BTC", + "currency":"FAC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/FAC" + }, + { + "id":"BTC_FCN", + "asset":"BTC", + "currency":"FCN", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/FCN" + }, + { + "id":"BTC_FCT", + "asset":"BTC", + "currency":"FCT", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/FCT" + }, + { + "id":"BTC_FIBRE", + "asset":"BTC", + "currency":"FIBRE", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/FIBRE" + }, + { + "id":"BTC_FLAP", + "asset":"BTC", + "currency":"FLAP", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/FLAP" + }, + { + "id":"BTC_FLDC", + "asset":"BTC", + "currency":"FLDC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/FLDC" + }, + { + "id":"BTC_FLO", + "asset":"BTC", + "currency":"FLO", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/FLO" + }, + { + "id":"BTC_FLT", + "asset":"BTC", + "currency":"FLT", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/FLT" + }, + { + "id":"BTC_FOX", + "asset":"BTC", + "currency":"FOX", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/FOX" + }, + { + "id":"BTC_FRAC", + "asset":"BTC", + "currency":"FRAC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/FRAC" + }, + { + "id":"BTC_FRK", + "asset":"BTC", + "currency":"FRK", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/" + }, + { + "id":"BTC_FRQ", + "asset":"BTC", + "currency":"FRQ", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/FRQ" + }, + { + "id":"BTC_FVZ", + "asset":"BTC", + "currency":"FVZ", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/FVZ" + }, + { + "id":"BTC_FZ", + "asset":"BTC", + "currency":"FZ", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/FZ" + }, + { + "id":"BTC_FZN", + "asset":"BTC", + "currency":"FZN", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/FZN" + }, + { + "id":"BTC_GAME", + "asset":"BTC", + "currency":"GAME", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/GAME" + }, + { + "id":"BTC_GAP", + "asset":"BTC", + "currency":"GAP", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/GAP" + }, + { + "id":"BTC_GDN", + "asset":"BTC", + "currency":"GDN", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/GDN" + }, + { + "id":"BTC_GEMZ", + "asset":"BTC", + "currency":"GEMZ", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/GEMZ" + }, + { + "id":"BTC_GEO", + "asset":"BTC", + "currency":"GEO", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/GEO" + }, + { + "id":"BTC_GIAR", + "asset":"BTC", + "currency":"GIAR", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/GIAR" + }, + { + "id":"BTC_GLB", + "asset":"BTC", + "currency":"GLB", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/GLB" + }, + { + "id":"BTC_GML", + "asset":"BTC", + "currency":"GML", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/GML" + }, + { + "id":"BTC_GNS", + "asset":"BTC", + "currency":"GNS", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/GNS" + }, + { + "id":"BTC_GOLD", + "asset":"BTC", + "currency":"GOLD", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/GOLD" + }, + { + "id":"BTC_GPC", + "asset":"BTC", + "currency":"GPC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/GPC" + }, + { + "id":"BTC_GPUC", + "asset":"BTC", + "currency":"GPUC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/GPUC" + }, + { + "id":"BTC_GRC", + "asset":"BTC", + "currency":"GRC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/GRC" + }, + { + "id":"BTC_GRS", + "asset":"BTC", + "currency":"GRS", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/GRS" + }, + { + "id":"BTC_GUE", + "asset":"BTC", + "currency":"GUE", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/GUE" + }, + { + "id":"BTC_H2O", + "asset":"BTC", + "currency":"H2O", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/H2O" + }, + { + "id":"BTC_HIRO", + "asset":"BTC", + "currency":"HIRO", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/HIRO" + }, + { + "id":"BTC_HOT", + "asset":"BTC", + "currency":"HOT", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/HOT" + }, + { + "id":"BTC_HUC", + "asset":"BTC", + "currency":"HUC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/HUC" + }, + { + "id":"BTC_HUGE", + "asset":"BTC", + "currency":"HUGE", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/HUGE" + }, + { + "id":"BTC_HVC", + "asset":"BTC", + "currency":"HVC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/HVC" + }, + { + "id":"BTC_HYP", + "asset":"BTC", + "currency":"HYP", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/HYP" + }, + { + "id":"BTC_HZ", + "asset":"BTC", + "currency":"HZ", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/HZ" + }, + { + "id":"BTC_IFC", + "asset":"BTC", + "currency":"IFC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/IFC" + }, + { + "id":"BTC_INDEX", + "asset":"BTC", + "currency":"INDEX", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/INDEX" + }, + { + "id":"BTC_IOC", + "asset":"BTC", + "currency":"IOC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/IOC" + }, + { + "id":"BTC_ITC", + "asset":"BTC", + "currency":"ITC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/ITC" + }, + { + "id":"BTC_IXC", + "asset":"BTC", + "currency":"IXC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/IXC" + }, + { + "id":"BTC_JLH", + "asset":"BTC", + "currency":"JLH", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/JLH" + }, + { + "id":"BTC_JPC", + "asset":"BTC", + "currency":"JPC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/JPC" + }, + { + "id":"BTC_JUG", + "asset":"BTC", + "currency":"JUG", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/JUG" + }, + { + "id":"BTC_KDC", + "asset":"BTC", + "currency":"KDC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/KDC" + }, + { + "id":"BTC_KEY", + "asset":"BTC", + "currency":"KEY", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/KEY" + }, + { + "id":"BTC_LBC", + "asset":"BTC", + "currency":"LBC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/LBC" + }, + { + "id":"BTC_LC", + "asset":"BTC", + "currency":"LC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/LC" + }, + { + "id":"BTC_LCL", + "asset":"BTC", + "currency":"LCL", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/LCL" + }, + { + "id":"BTC_LEAF", + "asset":"BTC", + "currency":"LEAF", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/LEAF" + }, + { + "id":"BTC_LGC", + "asset":"BTC", + "currency":"LGC", + "min_size":0.0001, + "max_size":10000, + "increment":0.01, + "label":"BTC/LGC" + }, ] -} \ No newline at end of file +} diff --git a/sample-config.js b/sample-config.js new file mode 100644 index 0000000000..72d21c00fa --- /dev/null +++ b/sample-config.js @@ -0,0 +1,1767 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + zenbot/config.js at master · carlos8f/zenbot · GitHub + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Skip to content + + + + + + + + + + + +
+ +
+
+ + +
+
+
+ +
+
+ + + + + +

+ + /zenbot + +

+ +
+ +
+ +
+
+ + + + + + + + + + +
+ + + 8c18845 + + Aug 14, 2016 + + + +
+ + +
+ + +
+ +
+
+
+ +
+ Raw + Blame + History +
+ + + + +
+ +
+ 263 lines (261 sloc) + + 8.91 KB +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
var c = module.exports = {}
c.mongo_url = "mongodb://localhost:27017/zenbrain" // change if your mongo server isn't local
c.mongo_username = null // normally not needed
c.mongo_password = null
c.bucket_size = "1m"
c.reducer_limit = 500 // how many thoughts to process per reduce run
c.reducer_sizes = ["1m", "5m", "15m", "1h", "6h", "1d"]
c.save_state_interval = 10000 // save state
c.parallel_limit = 8 // run this many concurrent tasks
c.reduce_timeout = 200
c.run_limit = 100
c.lock_timeout = 60000
c.lock_backoff = 20
c.lock_tries = 100
c.passive_update_timeout = 5000
c.return_timeout = 60000
c.brain_speed_ms = 200
c.twitter_key = "" // create a twitter app, generate an access token, and add it here
c.twitter_secret = ""
c.twitter_access_token = ""
c.twitter_access_token_secret = ""
c.assets = [
"BTC",
//"ETH",
//"LTC"
]
c.currencies = [
//"CNY",
//"EUR",
"USD"
]
c.enabled_plugins = [
//"bitfinex",
"gdax",
//"poloniex",
"server"
]
c.default_graph_period = "1h"
c.default_graph_limit = 300
c.graph_limits = [50, 100, 150, 200, 300, 500, 1000, 2000]
c.graph_selectors = [
"gdax.BTC-USD",
//"gdax.BTC-EUR",
//"gdax.ETH-USD",
//"poloniex.BTC-USD",
//"bitfinex.BTC-USD",
//"bitfinex.ETH-USD",
//"bitfinex.ETH-BTC",
//"bitfinex.ETC-BTC",
//"bitfinex.LTC-USD",
//"bitfinex.LTC-BTC",
//"bitfinex.ETC-BTC",
//"bitfinex.ETC-USD"
]
c.rsi_query_limit = 100
c.rsi_periods = 14
c.rsi_reporter_selector = "gdax.BTC-USD"
c.rsi_sizes = ['15m', '1h', '6h']
c.key = '' // TO ENABLE BOT TRADING: set this to GDAX api key,
c.secret = '' // set this to GDAX api secret,
c.passphrase = '' // set this to GDAX api passphrase.
var first_run = true
var last_balance_sig
c.logic = function container (get, set, clear) {
var o = get('utils.object_get')
var n = require('numbro')
var sig = require('sig')
var format_currency = get('utils.format_currency')
var get_timestamp = get('utils.get_timestamp')
var CoinbaseExchange = require('coinbase-exchange')
var client = new CoinbaseExchange.AuthenticatedClient(c.key, c.secret, c.passphrase)
var asset = 'BTC'
var currency = 'USD'
var rsi_period = '6h'
var exchange = 'gdax'
var selector = 'data.trades.' + exchange + '.' + asset + '-' + currency
function onOrder (err, resp, order) {
if (err) return get('logger').error('order err', err, resp, order, {feed: 'errors'})
if (resp.statusCode !== 200) {
console.error(order)
return get('logger').error('non-200 status: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: order}})
}
get('logger').info(exchange, ('order-id: ' + order.id).cyan, {data: {order: order}})
function getStatus () {
client.getOrder(order.id, function (err, resp, order) {
if (err) return get('logger').error('getOrder err', err)
if (resp.statusCode !== 200) {
console.error(order)
return get('logger').error('non-200 status from getOrder: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: order}})
}
if (order.status === 'done') {
return get('logger').info(exchange, ('order ' + order.id + ' done: ' + order.done_reason).cyan, {data: {order: order}})
}
else {
get('logger').info(exchange, ('order ' + order.id + ' ' + order.status).cyan, {data: {order: order}})
setTimeout(getStatus, 5000)
}
})
}
getStatus()
}
return [
// BEGIN DEFAULT TRADE LOGIC
// sync balance
function (tick, trigger, rs, cb) {
if (get('command') !== 'run' || !c.key) {
return cb()
}
client.getAccounts(function (err, resp, accounts) {
if (err) throw err
if (resp.statusCode !== 200) {
console.error(accounts)
get('logger').error('non-200 status from exchange: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: accounts}})
return cb && cb()
}
rs.balance = {}
accounts.forEach(function (account) {
if (account.currency === currency) {
rs.balance[currency] = n(account.balance).value()
}
else if (account.currency === asset) {
rs.balance[asset] = n(account.balance).value()
}
})
var balance_sig = sig(rs.balance)
if (balance_sig !== last_balance_sig) {
get('logger').info(exchange, 'balance'.grey, n(rs.balance[asset]).format('0.000').white, asset.grey, n(rs.balance[currency]).format('0.00').yellow, currency.grey, {feed: 'exchange'})
first_run = false
last_balance_sig = balance_sig
}
cb && cb()
})
},
function (tick, trigger, rs, cb) {
// note the last close price
var market_price = o(tick, selector + '.close')
if (market_price) {
rs.market_price = market_price
}
if (!rs.market_price) return cb()
if (!rs.balance) {
// start with $1000, neutral position
rs.balance = {}
rs.balance[currency] = 500
rs.balance[asset] = n(500).divide(rs.market_price).value()
}
rs.ticks || (rs.ticks = 0)
rs.ticks++
if (tick.size !== rsi_period) return cb()
// get rsi
var rsi = o(tick, selector + '.rsi')
// require minimum data
// overbought/oversold
// sanity check
if (rsi && rsi.samples >= c.rsi_periods) {
rs.rsi = Math.round(rsi.value)
rs.rsi_ansi = rsi.ansi
if (rsi.value > 70) {
rs.overbought = true
rs.oversold = false
}
else if (rsi.value < 30) {
rs.oversold = true
rs.overbought = false
}
}
cb()
},
// @todo MACD
function (tick, trigger, rs, cb) {
cb()
},
// trigger trade signals
function (tick, trigger, rs, cb) {
if ((rs.overbought || rs.oversold) && rs.balance && rs.market_price) {
var size, new_balance = {}
if (rs.overbought) {
get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, 'anticipating a reversal DOWN. sell at market. (' + format_currency(rs.market_price, currency) + ')', {feed: 'trader'})
size = rs.balance[asset]
}
else if (rs.oversold) {
get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, 'anticipating a reversal UP. buy at market. (' + format_currency(rs.market_price, currency) + ')', {feed: 'trader'})
size = n(rs.balance[currency]).divide(rs.market_price).value()
}
// scale down size a little, to prevent out-of-balance errors
size = n(size || 0).multiply(0.95).value()
// min size
if (!size || size < 0.01) {
if (rs.overbought) {
get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, ('not enough ' + asset + ' to execute sell!').red, {feed: 'trader'})
}
else if (rs.oversold) {
get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, ('not enough ' + currency + ' to execute buy!').red, {feed: 'trader'})
}
rs.overbought = rs.oversold = false
return cb()
}
if (rs.overbought) {
new_balance[currency] = n(rs.balance[currency]).add(n(size).multiply(rs.market_price)).value()
new_balance[asset] = n(rs.balance[asset]).subtract(size).value()
}
else if (rs.oversold) {
new_balance[asset] = n(rs.balance[asset]).add(size).value()
new_balance[currency] = n(rs.balance[currency]).subtract(n(size).multiply(rs.market_price)).value()
}
// consolidate balance
var new_end_balance = n(new_balance[currency]).add(n(new_balance[asset]).multiply(rs.market_price)).value()
var new_roi = n(new_end_balance).divide(1000).value()
rs.balance = new_balance
rs.end_balance = new_end_balance
rs.roi = new_roi
rs.trades || (rs.trades = 0)
rs.trades++
trigger({
type: rs.overbought ? 'sell' : 'buy',
asset: asset,
currency: currency,
exchange: exchange,
price: rs.market_price,
market: true,
size: size,
rsi: rs.rsi,
roi: rs.roi
})
if (get('command') === 'run' && c.key) {
var params = {
type: 'market',
size: n(size).format('0.000000'),
product_id: asset + '-' + currency
}
client[rs.overbought ? 'sell' : 'buy'](params, function (err, resp, order) {
onOrder(err, resp, order)
})
}
rs.overbought = rs.oversold = false
}
cb()
}
// END DEFAULT TRADE LOGIC
]
}
c.reporter_sizes = ['1m', '15m', '1h', '6h']
c.price_reporter_selector = "gdax.BTC-USD"
c.price_reporter_length = 9
c.reporter_cols = [
"tick_id",
"num_trades",
"timestamp",
"rsi",
"volume",
"price"
]
c.backfill_days = 91
c.record_timeout = 20000
c.backfill_timeout = 5000
c.reducer_report_interval = 2000
c.trade_report_interval = 10000
c.sim_input_unit = "7d"
c.sim_input_limit = 12
c.log_query_limit = 200
c.tracking_scripts = ''
+
+ +
+ +
+ + + + +
+ +
+ + +
+
+ +
+ + + + + + + +
+ + + You can't perform that action at this time. +
+ + + + + + + + + + + + + + + + + From dcae889f4fa17931559982a362ff7cd4b757078f Mon Sep 17 00:00:00 2001 From: RDash Date: Mon, 15 Aug 2016 18:55:31 +0200 Subject: [PATCH 21/56] Fixed an oopsy in config.js --- sample-config.js | 2027 ++++++---------------------------------------- 1 file changed, 261 insertions(+), 1766 deletions(-) diff --git a/sample-config.js b/sample-config.js index 72d21c00fa..67b7d4f8fe 100644 --- a/sample-config.js +++ b/sample-config.js @@ -1,1767 +1,262 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - zenbot/config.js at master · carlos8f/zenbot · GitHub - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Skip to content - - - - - - - - - - - -
- -
-
- - -
-
-
- -
-
- - - - - -

- - /zenbot - -

- -
- -
- -
-
- - - - - - - - - - -
- - - 8c18845 - - Aug 14, 2016 - - - -
- - -
- - -
- -
-
-
- -
- Raw - Blame - History -
- - - - -
- -
- 263 lines (261 sloc) - - 8.91 KB -
-
- - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
var c = module.exports = {}
c.mongo_url = "mongodb://localhost:27017/zenbrain" // change if your mongo server isn't local
c.mongo_username = null // normally not needed
c.mongo_password = null
c.bucket_size = "1m"
c.reducer_limit = 500 // how many thoughts to process per reduce run
c.reducer_sizes = ["1m", "5m", "15m", "1h", "6h", "1d"]
c.save_state_interval = 10000 // save state
c.parallel_limit = 8 // run this many concurrent tasks
c.reduce_timeout = 200
c.run_limit = 100
c.lock_timeout = 60000
c.lock_backoff = 20
c.lock_tries = 100
c.passive_update_timeout = 5000
c.return_timeout = 60000
c.brain_speed_ms = 200
c.twitter_key = "" // create a twitter app, generate an access token, and add it here
c.twitter_secret = ""
c.twitter_access_token = ""
c.twitter_access_token_secret = ""
c.assets = [
"BTC",
//"ETH",
//"LTC"
]
c.currencies = [
//"CNY",
//"EUR",
"USD"
]
c.enabled_plugins = [
//"bitfinex",
"gdax",
//"poloniex",
"server"
]
c.default_graph_period = "1h"
c.default_graph_limit = 300
c.graph_limits = [50, 100, 150, 200, 300, 500, 1000, 2000]
c.graph_selectors = [
"gdax.BTC-USD",
//"gdax.BTC-EUR",
//"gdax.ETH-USD",
//"poloniex.BTC-USD",
//"bitfinex.BTC-USD",
//"bitfinex.ETH-USD",
//"bitfinex.ETH-BTC",
//"bitfinex.ETC-BTC",
//"bitfinex.LTC-USD",
//"bitfinex.LTC-BTC",
//"bitfinex.ETC-BTC",
//"bitfinex.ETC-USD"
]
c.rsi_query_limit = 100
c.rsi_periods = 14
c.rsi_reporter_selector = "gdax.BTC-USD"
c.rsi_sizes = ['15m', '1h', '6h']
c.key = '' // TO ENABLE BOT TRADING: set this to GDAX api key,
c.secret = '' // set this to GDAX api secret,
c.passphrase = '' // set this to GDAX api passphrase.
var first_run = true
var last_balance_sig
c.logic = function container (get, set, clear) {
var o = get('utils.object_get')
var n = require('numbro')
var sig = require('sig')
var format_currency = get('utils.format_currency')
var get_timestamp = get('utils.get_timestamp')
var CoinbaseExchange = require('coinbase-exchange')
var client = new CoinbaseExchange.AuthenticatedClient(c.key, c.secret, c.passphrase)
var asset = 'BTC'
var currency = 'USD'
var rsi_period = '6h'
var exchange = 'gdax'
var selector = 'data.trades.' + exchange + '.' + asset + '-' + currency
function onOrder (err, resp, order) {
if (err) return get('logger').error('order err', err, resp, order, {feed: 'errors'})
if (resp.statusCode !== 200) {
console.error(order)
return get('logger').error('non-200 status: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: order}})
}
get('logger').info(exchange, ('order-id: ' + order.id).cyan, {data: {order: order}})
function getStatus () {
client.getOrder(order.id, function (err, resp, order) {
if (err) return get('logger').error('getOrder err', err)
if (resp.statusCode !== 200) {
console.error(order)
return get('logger').error('non-200 status from getOrder: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: order}})
}
if (order.status === 'done') {
return get('logger').info(exchange, ('order ' + order.id + ' done: ' + order.done_reason).cyan, {data: {order: order}})
}
else {
get('logger').info(exchange, ('order ' + order.id + ' ' + order.status).cyan, {data: {order: order}})
setTimeout(getStatus, 5000)
}
})
}
getStatus()
}
return [
// BEGIN DEFAULT TRADE LOGIC
// sync balance
function (tick, trigger, rs, cb) {
if (get('command') !== 'run' || !c.key) {
return cb()
}
client.getAccounts(function (err, resp, accounts) {
if (err) throw err
if (resp.statusCode !== 200) {
console.error(accounts)
get('logger').error('non-200 status from exchange: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: accounts}})
return cb && cb()
}
rs.balance = {}
accounts.forEach(function (account) {
if (account.currency === currency) {
rs.balance[currency] = n(account.balance).value()
}
else if (account.currency === asset) {
rs.balance[asset] = n(account.balance).value()
}
})
var balance_sig = sig(rs.balance)
if (balance_sig !== last_balance_sig) {
get('logger').info(exchange, 'balance'.grey, n(rs.balance[asset]).format('0.000').white, asset.grey, n(rs.balance[currency]).format('0.00').yellow, currency.grey, {feed: 'exchange'})
first_run = false
last_balance_sig = balance_sig
}
cb && cb()
})
},
function (tick, trigger, rs, cb) {
// note the last close price
var market_price = o(tick, selector + '.close')
if (market_price) {
rs.market_price = market_price
}
if (!rs.market_price) return cb()
if (!rs.balance) {
// start with $1000, neutral position
rs.balance = {}
rs.balance[currency] = 500
rs.balance[asset] = n(500).divide(rs.market_price).value()
}
rs.ticks || (rs.ticks = 0)
rs.ticks++
if (tick.size !== rsi_period) return cb()
// get rsi
var rsi = o(tick, selector + '.rsi')
// require minimum data
// overbought/oversold
// sanity check
if (rsi && rsi.samples >= c.rsi_periods) {
rs.rsi = Math.round(rsi.value)
rs.rsi_ansi = rsi.ansi
if (rsi.value > 70) {
rs.overbought = true
rs.oversold = false
}
else if (rsi.value < 30) {
rs.oversold = true
rs.overbought = false
}
}
cb()
},
// @todo MACD
function (tick, trigger, rs, cb) {
cb()
},
// trigger trade signals
function (tick, trigger, rs, cb) {
if ((rs.overbought || rs.oversold) && rs.balance && rs.market_price) {
var size, new_balance = {}
if (rs.overbought) {
get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, 'anticipating a reversal DOWN. sell at market. (' + format_currency(rs.market_price, currency) + ')', {feed: 'trader'})
size = rs.balance[asset]
}
else if (rs.oversold) {
get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, 'anticipating a reversal UP. buy at market. (' + format_currency(rs.market_price, currency) + ')', {feed: 'trader'})
size = n(rs.balance[currency]).divide(rs.market_price).value()
}
// scale down size a little, to prevent out-of-balance errors
size = n(size || 0).multiply(0.95).value()
// min size
if (!size || size < 0.01) {
if (rs.overbought) {
get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, ('not enough ' + asset + ' to execute sell!').red, {feed: 'trader'})
}
else if (rs.oversold) {
get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, ('not enough ' + currency + ' to execute buy!').red, {feed: 'trader'})
}
rs.overbought = rs.oversold = false
return cb()
}
if (rs.overbought) {
new_balance[currency] = n(rs.balance[currency]).add(n(size).multiply(rs.market_price)).value()
new_balance[asset] = n(rs.balance[asset]).subtract(size).value()
}
else if (rs.oversold) {
new_balance[asset] = n(rs.balance[asset]).add(size).value()
new_balance[currency] = n(rs.balance[currency]).subtract(n(size).multiply(rs.market_price)).value()
}
// consolidate balance
var new_end_balance = n(new_balance[currency]).add(n(new_balance[asset]).multiply(rs.market_price)).value()
var new_roi = n(new_end_balance).divide(1000).value()
rs.balance = new_balance
rs.end_balance = new_end_balance
rs.roi = new_roi
rs.trades || (rs.trades = 0)
rs.trades++
trigger({
type: rs.overbought ? 'sell' : 'buy',
asset: asset,
currency: currency,
exchange: exchange,
price: rs.market_price,
market: true,
size: size,
rsi: rs.rsi,
roi: rs.roi
})
if (get('command') === 'run' && c.key) {
var params = {
type: 'market',
size: n(size).format('0.000000'),
product_id: asset + '-' + currency
}
client[rs.overbought ? 'sell' : 'buy'](params, function (err, resp, order) {
onOrder(err, resp, order)
})
}
rs.overbought = rs.oversold = false
}
cb()
}
// END DEFAULT TRADE LOGIC
]
}
c.reporter_sizes = ['1m', '15m', '1h', '6h']
c.price_reporter_selector = "gdax.BTC-USD"
c.price_reporter_length = 9
c.reporter_cols = [
"tick_id",
"num_trades",
"timestamp",
"rsi",
"volume",
"price"
]
c.backfill_days = 91
c.record_timeout = 20000
c.backfill_timeout = 5000
c.reducer_report_interval = 2000
c.trade_report_interval = 10000
c.sim_input_unit = "7d"
c.sim_input_limit = 12
c.log_query_limit = 200
c.tracking_scripts = ''
-
- -
- -
- - - - -
- -
- - -
-
- -
- - - - - - - -
- - - You can't perform that action at this time. -
- - - - - - - - - - - - - - - - +var c = module.exports = {} +c.mongo_url = "mongodb://localhost:27017/zenbrain" // change if your mongo server isn't local +c.mongo_username = null // normally not needed +c.mongo_password = null +c.bucket_size = "1m" +c.reducer_limit = 500 // how many thoughts to process per reduce run +c.reducer_sizes = ["1m", "5m", "15m", "1h", "6h", "1d"] +c.save_state_interval = 10000 // save state +c.parallel_limit = 8 // run this many concurrent tasks +c.reduce_timeout = 200 +c.run_limit = 100 +c.lock_timeout = 60000 +c.lock_backoff = 20 +c.lock_tries = 100 +c.passive_update_timeout = 5000 +c.return_timeout = 60000 +c.brain_speed_ms = 200 +c.twitter_key = "" // create a twitter app, generate an access token, and add it here +c.twitter_secret = "" +c.twitter_access_token = "" +c.twitter_access_token_secret = "" +c.assets = [ + "BTC", + //"ETH", + //"LTC" +] +c.currencies = [ + //"CNY", + //"EUR", + "USD" +] +c.enabled_plugins = [ + //"bitfinex", + "gdax", + //"poloniex", + "server" +] +c.default_graph_period = "1h" +c.default_graph_limit = 300 +c.graph_limits = [50, 100, 150, 200, 300, 500, 1000, 2000] +c.graph_selectors = [ + "gdax.BTC-USD", + //"gdax.BTC-EUR", + //"gdax.ETH-USD", + //"poloniex.BTC-USD", + //"bitfinex.BTC-USD", + //"bitfinex.ETH-USD", + //"bitfinex.ETH-BTC", + //"bitfinex.ETC-BTC", + //"bitfinex.LTC-USD", + //"bitfinex.LTC-BTC", + //"bitfinex.ETC-BTC", + //"bitfinex.ETC-USD" +] +c.rsi_query_limit = 100 +c.rsi_periods = 14 +c.rsi_reporter_selector = "gdax.BTC-USD" +c.rsi_sizes = ['15m', '1h', '6h'] +c.key = '' // TO ENABLE BOT TRADING: set this to GDAX api key, +c.secret = '' // set this to GDAX api secret, +c.passphrase = '' // set this to GDAX api passphrase. +var first_run = true +var last_balance_sig +c.logic = function container (get, set, clear) { + var o = get('utils.object_get') + var n = require('numbro') + var sig = require('sig') + var format_currency = get('utils.format_currency') + var get_timestamp = get('utils.get_timestamp') + var CoinbaseExchange = require('coinbase-exchange') + var client = new CoinbaseExchange.AuthenticatedClient(c.key, c.secret, c.passphrase) + var asset = 'BTC' + var currency = 'USD' + var rsi_period = '6h' + var exchange = 'gdax' + var selector = 'data.trades.' + exchange + '.' + asset + '-' + currency + function onOrder (err, resp, order) { + if (err) return get('logger').error('order err', err, resp, order, {feed: 'errors'}) + if (resp.statusCode !== 200) { + console.error(order) + return get('logger').error('non-200 status: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: order}}) + } + get('logger').info(exchange, ('order-id: ' + order.id).cyan, {data: {order: order}}) + function getStatus () { + client.getOrder(order.id, function (err, resp, order) { + if (err) return get('logger').error('getOrder err', err) + if (resp.statusCode !== 200) { + console.error(order) + return get('logger').error('non-200 status from getOrder: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: order}}) + } + if (order.status === 'done') { + return get('logger').info(exchange, ('order ' + order.id + ' done: ' + order.done_reason).cyan, {data: {order: order}}) + } + else { + get('logger').info(exchange, ('order ' + order.id + ' ' + order.status).cyan, {data: {order: order}}) + setTimeout(getStatus, 5000) + } + }) + } + getStatus() + } + return [ + // BEGIN DEFAULT TRADE LOGIC + // sync balance + function (tick, trigger, rs, cb) { + if (get('command') !== 'run' || !c.key) { + return cb() + } + client.getAccounts(function (err, resp, accounts) { + if (err) throw err + if (resp.statusCode !== 200) { + console.error(accounts) + get('logger').error('non-200 status from exchange: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: accounts}}) + return cb && cb() + } + rs.balance = {} + accounts.forEach(function (account) { + if (account.currency === currency) { + rs.balance[currency] = n(account.balance).value() + } + else if (account.currency === asset) { + rs.balance[asset] = n(account.balance).value() + } + }) + var balance_sig = sig(rs.balance) + if (balance_sig !== last_balance_sig) { + get('logger').info(exchange, 'balance'.grey, n(rs.balance[asset]).format('0.000').white, asset.grey, n(rs.balance[currency]).format('0.00').yellow, currency.grey, {feed: 'exchange'}) + first_run = false + last_balance_sig = balance_sig + } + cb && cb() + }) + }, + function (tick, trigger, rs, cb) { + // note the last close price + var market_price = o(tick, selector + '.close') + if (market_price) { + rs.market_price = market_price + } + if (!rs.market_price) return cb() + if (!rs.balance) { + // start with $1000, neutral position + rs.balance = {} + rs.balance[currency] = 500 + rs.balance[asset] = n(500).divide(rs.market_price).value() + } + rs.ticks || (rs.ticks = 0) + rs.ticks++ + if (tick.size !== rsi_period) return cb() + // get rsi + var rsi = o(tick, selector + '.rsi') + // require minimum data + // overbought/oversold + // sanity check + if (rsi && rsi.samples >= c.rsi_periods) { + rs.rsi = Math.round(rsi.value) + rs.rsi_ansi = rsi.ansi + if (rsi.value > 70) { + rs.overbought = true + rs.oversold = false + } + else if (rsi.value < 30) { + rs.oversold = true + rs.overbought = false + } + } + cb() + }, + // @todo MACD + function (tick, trigger, rs, cb) { + cb() + }, + // trigger trade signals + function (tick, trigger, rs, cb) { + if ((rs.overbought || rs.oversold) && rs.balance && rs.market_price) { + var size, new_balance = {} + if (rs.overbought) { + get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, 'anticipating a reversal DOWN. sell at market. (' + format_currency(rs.market_price, currency) + ')', {feed: 'trader'}) + size = rs.balance[asset] + } + else if (rs.oversold) { + get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, 'anticipating a reversal UP. buy at market. (' + format_currency(rs.market_price, currency) + ')', {feed: 'trader'}) + size = n(rs.balance[currency]).divide(rs.market_price).value() + } + // scale down size a little, to prevent out-of-balance errors + size = n(size || 0).multiply(0.95).value() + // min size + if (!size || size < 0.01) { + if (rs.overbought) { + get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, ('not enough ' + asset + ' to execute sell!').red, {feed: 'trader'}) + } + else if (rs.oversold) { + get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, ('not enough ' + currency + ' to execute buy!').red, {feed: 'trader'}) + } + rs.overbought = rs.oversold = false + return cb() + } + if (rs.overbought) { + new_balance[currency] = n(rs.balance[currency]).add(n(size).multiply(rs.market_price)).value() + new_balance[asset] = n(rs.balance[asset]).subtract(size).value() + } + else if (rs.oversold) { + new_balance[asset] = n(rs.balance[asset]).add(size).value() + new_balance[currency] = n(rs.balance[currency]).subtract(n(size).multiply(rs.market_price)).value() + } + // consolidate balance + var new_end_balance = n(new_balance[currency]).add(n(new_balance[asset]).multiply(rs.market_price)).value() + var new_roi = n(new_end_balance).divide(1000).value() + rs.balance = new_balance + rs.end_balance = new_end_balance + rs.roi = new_roi + rs.trades || (rs.trades = 0) + rs.trades++ + trigger({ + type: rs.overbought ? 'sell' : 'buy', + asset: asset, + currency: currency, + exchange: exchange, + price: rs.market_price, + market: true, + size: size, + rsi: rs.rsi, + roi: rs.roi + }) + if (get('command') === 'run' && c.key) { + var params = { + type: 'market', + size: n(size).format('0.000000'), + product_id: asset + '-' + currency + } + client[rs.overbought ? 'sell' : 'buy'](params, function (err, resp, order) { + onOrder(err, resp, order) + }) + } + rs.overbought = rs.oversold = false + } + cb() + } + // END DEFAULT TRADE LOGIC + ] +} +c.reporter_sizes = ['1m', '15m', '1h', '6h'] +c.price_reporter_selector = "gdax.BTC-USD" +c.price_reporter_length = 9 +c.reporter_cols = [ + "tick_id", + "num_trades", + "timestamp", + "rsi", + "volume", + "price" +] +c.backfill_days = 91 +c.record_timeout = 20000 +c.backfill_timeout = 5000 +c.reducer_report_interval = 2000 +c.trade_report_interval = 10000 +c.sim_input_unit = "7d" +c.sim_input_limit = 12 +c.log_query_limit = 200 +c.tracking_scripts = '' From 8e40bb77a18461321ff9863c61feae86d985c453 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 10:26:57 -0700 Subject: [PATCH 22/56] progress indicator --- config.js | 22 ++++++++++++++++------ core/indicators/_codemap.js | 1 + core/indicators/progress/_codemap.js | 4 ++++ core/indicators/progress/reporter_col.js | 12 ++++++++++++ core/reporter.js | 3 ++- 5 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 core/indicators/progress/_codemap.js create mode 100644 core/indicators/progress/reporter_col.js diff --git a/config.js b/config.js index 67b7d4f8fe..ebbfc43c22 100644 --- a/config.js +++ b/config.js @@ -64,6 +64,7 @@ var last_balance_sig c.logic = function container (get, set, clear) { var o = get('utils.object_get') var n = require('numbro') + var tb = require('timebucket') var sig = require('sig') var format_currency = get('utils.format_currency') var get_timestamp = get('utils.get_timestamp') @@ -137,6 +138,8 @@ c.logic = function container (get, set, clear) { if (market_price) { rs.market_price = market_price } + rs.ticks || (rs.ticks = 0) + rs.progress || (rs.progress = 0) if (!rs.market_price) return cb() if (!rs.balance) { // start with $1000, neutral position @@ -144,9 +147,15 @@ c.logic = function container (get, set, clear) { rs.balance[currency] = 500 rs.balance[asset] = n(500).divide(rs.market_price).value() } - rs.ticks || (rs.ticks = 0) rs.ticks++ - if (tick.size !== rsi_period) return cb() + if (tick.size !== rsi_period) { + // what % are we to a decision? + var base_time = tb(tick.time).resize(rsi_period).toMilliseconds() + var target_time = tb(tick.time).resize(rsi_period).add(1).toMilliseconds() + rs.progress = n(tick.time - base_time).divide(target_time - base_time).value() + return cb() + } + rs.progress = 1 // get rsi var rsi = o(tick, selector + '.rsi') // require minimum data @@ -239,7 +248,7 @@ c.logic = function container (get, set, clear) { // END DEFAULT TRADE LOGIC ] } -c.reporter_sizes = ['1m', '15m', '1h', '6h'] +c.reporter_sizes = ['15m', '1h', '6h'] c.price_reporter_selector = "gdax.BTC-USD" c.price_reporter_length = 9 c.reporter_cols = [ @@ -248,13 +257,14 @@ c.reporter_cols = [ "timestamp", "rsi", "volume", - "price" + "price", + "progress" ] c.backfill_days = 91 c.record_timeout = 20000 c.backfill_timeout = 5000 -c.reducer_report_interval = 2000 -c.trade_report_interval = 10000 +c.reducer_report_interval = 10000 +c.trade_report_interval = 60000 c.sim_input_unit = "7d" c.sim_input_limit = 12 c.log_query_limit = 200 diff --git a/core/indicators/_codemap.js b/core/indicators/_codemap.js index c45ce81d3d..32567f9966 100644 --- a/core/indicators/_codemap.js +++ b/core/indicators/_codemap.js @@ -3,6 +3,7 @@ module.exports = { _maps: [ require('./num_trades/_codemap'), require('./price/_codemap'), + require('./progress/_codemap'), require('./rsi/_codemap'), require('./tick_id/_codemap'), require('./timestamp/_codemap'), diff --git a/core/indicators/progress/_codemap.js b/core/indicators/progress/_codemap.js new file mode 100644 index 0000000000..f6749927c1 --- /dev/null +++ b/core/indicators/progress/_codemap.js @@ -0,0 +1,4 @@ +module.exports = { + _ns: 'zenbrain', + 'reporter_cols.progress': require('./reporter_col') +} \ No newline at end of file diff --git a/core/indicators/progress/reporter_col.js b/core/indicators/progress/reporter_col.js new file mode 100644 index 0000000000..4739b54b61 --- /dev/null +++ b/core/indicators/progress/reporter_col.js @@ -0,0 +1,12 @@ +var colors = require('colors') + , n = require('numbro') + +module.exports = function container (get, set, clear) { + var c = get('config') + var z = get('utils.zero_fill') + return function reporter_col (g, cb) { + var line = z(4, n(g.rs.progress).format('0%')).yellow + g.cols.push(line) + cb() + } +} \ No newline at end of file diff --git a/core/reporter.js b/core/reporter.js index c4a967baeb..be0243a5e3 100644 --- a/core/reporter.js +++ b/core/reporter.js @@ -12,7 +12,8 @@ module.exports = function container (get, set, clear) { if (c.reporter_sizes.indexOf(tick.size) === -1 || !tick.data.trades) return cb() var g = { tick: tick, - cols: [] + cols: [], + rs: rs } apply_funcs(g, reporter_cols, function (err, g) { if (err) return cb(err) From 67efbc906afebdb30a6c778aed316675ce5916ea Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 15:33:43 -0700 Subject: [PATCH 23/56] 3.1 - fixed default trade logic, reconfig of rsi handling --- config.js | 269 ++++++---------------------- core/action_handler.js | 2 +- core/indicators/rsi/_codemap.js | 25 +-- core/indicators/rsi/backfiller.js | 6 +- core/indicators/rsi/tick_reducer.js | 2 +- default_logic.js | 230 ++++++++++++++++++++++++ plugins/gdax/backfiller.js | 2 +- plugins/gdax/recorder.js | 2 +- plugins/server/_codemap.js | 2 +- plugins/server/controllers/data.js | 3 - utils/is_backfilled.js | 7 +- 11 files changed, 296 insertions(+), 254 deletions(-) create mode 100644 default_logic.js diff --git a/config.js b/config.js index ebbfc43c22..f2085a53a3 100644 --- a/config.js +++ b/config.js @@ -1,24 +1,15 @@ var c = module.exports = {} + +c.key = '' // TO ENABLE BOT TRADING: set this to GDAX api key, +c.secret = '' // set this to GDAX api secret, +c.passphrase = '' // set this to GDAX api passphrase. + +// mongo stuff c.mongo_url = "mongodb://localhost:27017/zenbrain" // change if your mongo server isn't local c.mongo_username = null // normally not needed c.mongo_password = null -c.bucket_size = "1m" -c.reducer_limit = 500 // how many thoughts to process per reduce run -c.reducer_sizes = ["1m", "5m", "15m", "1h", "6h", "1d"] -c.save_state_interval = 10000 // save state -c.parallel_limit = 8 // run this many concurrent tasks -c.reduce_timeout = 200 -c.run_limit = 100 -c.lock_timeout = 60000 -c.lock_backoff = 20 -c.lock_tries = 100 -c.passive_update_timeout = 5000 -c.return_timeout = 60000 -c.brain_speed_ms = 200 -c.twitter_key = "" // create a twitter app, generate an access token, and add it here -c.twitter_secret = "" -c.twitter_access_token = "" -c.twitter_access_token_secret = "" + +// add assets/currencies you want to track c.assets = [ "BTC", //"ETH", @@ -29,12 +20,21 @@ c.currencies = [ //"EUR", "USD" ] +// will require(plugins/{name}/_codemap or {name}/_codemap) c.enabled_plugins = [ //"bitfinex", "gdax", //"poloniex", "server" ] + +// twitter stuff +c.twitter_key = "" // create a twitter app, generate an access token, and add it here +c.twitter_secret = "" +c.twitter_access_token = "" +c.twitter_access_token_secret = "" + +// graph server c.default_graph_period = "1h" c.default_graph_limit = 300 c.graph_limits = [50, 100, 150, 200, 300, 500, 1000, 2000] @@ -52,203 +52,20 @@ c.graph_selectors = [ //"bitfinex.ETC-BTC", //"bitfinex.ETC-USD" ] +c.log_query_limit = 200 +c.tracking_scripts = '' + +// RSI indicator config +c.rsi_sizes = ['15m'] +c.rsi_reporter_selector = "gdax.BTC-USD" c.rsi_query_limit = 100 c.rsi_periods = 14 -c.rsi_reporter_selector = "gdax.BTC-USD" -c.rsi_sizes = ['15m', '1h', '6h'] -c.key = '' // TO ENABLE BOT TRADING: set this to GDAX api key, -c.secret = '' // set this to GDAX api secret, -c.passphrase = '' // set this to GDAX api passphrase. -var first_run = true -var last_balance_sig -c.logic = function container (get, set, clear) { - var o = get('utils.object_get') - var n = require('numbro') - var tb = require('timebucket') - var sig = require('sig') - var format_currency = get('utils.format_currency') - var get_timestamp = get('utils.get_timestamp') - var CoinbaseExchange = require('coinbase-exchange') - var client = new CoinbaseExchange.AuthenticatedClient(c.key, c.secret, c.passphrase) - var asset = 'BTC' - var currency = 'USD' - var rsi_period = '6h' - var exchange = 'gdax' - var selector = 'data.trades.' + exchange + '.' + asset + '-' + currency - function onOrder (err, resp, order) { - if (err) return get('logger').error('order err', err, resp, order, {feed: 'errors'}) - if (resp.statusCode !== 200) { - console.error(order) - return get('logger').error('non-200 status: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: order}}) - } - get('logger').info(exchange, ('order-id: ' + order.id).cyan, {data: {order: order}}) - function getStatus () { - client.getOrder(order.id, function (err, resp, order) { - if (err) return get('logger').error('getOrder err', err) - if (resp.statusCode !== 200) { - console.error(order) - return get('logger').error('non-200 status from getOrder: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: order}}) - } - if (order.status === 'done') { - return get('logger').info(exchange, ('order ' + order.id + ' done: ' + order.done_reason).cyan, {data: {order: order}}) - } - else { - get('logger').info(exchange, ('order ' + order.id + ' ' + order.status).cyan, {data: {order: order}}) - setTimeout(getStatus, 5000) - } - }) - } - getStatus() - } - return [ - // BEGIN DEFAULT TRADE LOGIC - // sync balance - function (tick, trigger, rs, cb) { - if (get('command') !== 'run' || !c.key) { - return cb() - } - client.getAccounts(function (err, resp, accounts) { - if (err) throw err - if (resp.statusCode !== 200) { - console.error(accounts) - get('logger').error('non-200 status from exchange: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: accounts}}) - return cb && cb() - } - rs.balance = {} - accounts.forEach(function (account) { - if (account.currency === currency) { - rs.balance[currency] = n(account.balance).value() - } - else if (account.currency === asset) { - rs.balance[asset] = n(account.balance).value() - } - }) - var balance_sig = sig(rs.balance) - if (balance_sig !== last_balance_sig) { - get('logger').info(exchange, 'balance'.grey, n(rs.balance[asset]).format('0.000').white, asset.grey, n(rs.balance[currency]).format('0.00').yellow, currency.grey, {feed: 'exchange'}) - first_run = false - last_balance_sig = balance_sig - } - cb && cb() - }) - }, - function (tick, trigger, rs, cb) { - // note the last close price - var market_price = o(tick, selector + '.close') - if (market_price) { - rs.market_price = market_price - } - rs.ticks || (rs.ticks = 0) - rs.progress || (rs.progress = 0) - if (!rs.market_price) return cb() - if (!rs.balance) { - // start with $1000, neutral position - rs.balance = {} - rs.balance[currency] = 500 - rs.balance[asset] = n(500).divide(rs.market_price).value() - } - rs.ticks++ - if (tick.size !== rsi_period) { - // what % are we to a decision? - var base_time = tb(tick.time).resize(rsi_period).toMilliseconds() - var target_time = tb(tick.time).resize(rsi_period).add(1).toMilliseconds() - rs.progress = n(tick.time - base_time).divide(target_time - base_time).value() - return cb() - } - rs.progress = 1 - // get rsi - var rsi = o(tick, selector + '.rsi') - // require minimum data - // overbought/oversold - // sanity check - if (rsi && rsi.samples >= c.rsi_periods) { - rs.rsi = Math.round(rsi.value) - rs.rsi_ansi = rsi.ansi - if (rsi.value > 70) { - rs.overbought = true - rs.oversold = false - } - else if (rsi.value < 30) { - rs.oversold = true - rs.overbought = false - } - } - cb() - }, - // @todo MACD - function (tick, trigger, rs, cb) { - cb() - }, - // trigger trade signals - function (tick, trigger, rs, cb) { - if ((rs.overbought || rs.oversold) && rs.balance && rs.market_price) { - var size, new_balance = {} - if (rs.overbought) { - get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, 'anticipating a reversal DOWN. sell at market. (' + format_currency(rs.market_price, currency) + ')', {feed: 'trader'}) - size = rs.balance[asset] - } - else if (rs.oversold) { - get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, 'anticipating a reversal UP. buy at market. (' + format_currency(rs.market_price, currency) + ')', {feed: 'trader'}) - size = n(rs.balance[currency]).divide(rs.market_price).value() - } - // scale down size a little, to prevent out-of-balance errors - size = n(size || 0).multiply(0.95).value() - // min size - if (!size || size < 0.01) { - if (rs.overbought) { - get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, ('not enough ' + asset + ' to execute sell!').red, {feed: 'trader'}) - } - else if (rs.oversold) { - get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, ('not enough ' + currency + ' to execute buy!').red, {feed: 'trader'}) - } - rs.overbought = rs.oversold = false - return cb() - } - if (rs.overbought) { - new_balance[currency] = n(rs.balance[currency]).add(n(size).multiply(rs.market_price)).value() - new_balance[asset] = n(rs.balance[asset]).subtract(size).value() - } - else if (rs.oversold) { - new_balance[asset] = n(rs.balance[asset]).add(size).value() - new_balance[currency] = n(rs.balance[currency]).subtract(n(size).multiply(rs.market_price)).value() - } - // consolidate balance - var new_end_balance = n(new_balance[currency]).add(n(new_balance[asset]).multiply(rs.market_price)).value() - var new_roi = n(new_end_balance).divide(1000).value() - rs.balance = new_balance - rs.end_balance = new_end_balance - rs.roi = new_roi - rs.trades || (rs.trades = 0) - rs.trades++ - trigger({ - type: rs.overbought ? 'sell' : 'buy', - asset: asset, - currency: currency, - exchange: exchange, - price: rs.market_price, - market: true, - size: size, - rsi: rs.rsi, - roi: rs.roi - }) - if (get('command') === 'run' && c.key) { - var params = { - type: 'market', - size: n(size).format('0.000000'), - product_id: asset + '-' + currency - } - client[rs.overbought ? 'sell' : 'buy'](params, function (err, resp, order) { - onOrder(err, resp, order) - }) - } - rs.overbought = rs.oversold = false - } - cb() - } - // END DEFAULT TRADE LOGIC - ] -} -c.reporter_sizes = ['15m', '1h', '6h'] + +// trade logic +c.logic = require('./default_logic') + +// reporter +c.reporter_sizes = ['15m'] c.price_reporter_selector = "gdax.BTC-USD" c.price_reporter_length = 9 c.reporter_cols = [ @@ -258,15 +75,31 @@ c.reporter_cols = [ "rsi", "volume", "price", - "progress" + //"progress" ] +c.reducer_report_interval = 5000 +c.trade_report_interval = 5000 + +// backfiller c.backfill_days = 91 c.record_timeout = 20000 -c.backfill_timeout = 5000 -c.reducer_report_interval = 10000 -c.trade_report_interval = 60000 +c.backfill_timeout = 500 + +// simulator c.sim_input_unit = "7d" c.sim_input_limit = 12 -c.log_query_limit = 200 -c.tracking_scripts = '' +// zenbrain engine stuff +c.bucket_size = "1m" +c.reducer_limit = 500 // how many thoughts to process per reduce run +c.reducer_sizes = ["1m", "5m", "15m", "1h", "6h", "1d"] +c.save_state_interval = 10000 // save state +c.parallel_limit = 8 // run this many concurrent tasks +c.reduce_timeout = 200 +c.run_limit = 100 +c.lock_timeout = 60000 +c.lock_backoff = 20 +c.lock_tries = 100 +c.passive_update_timeout = 5000 +c.return_timeout = 60000 +c.brain_speed_ms = 200 diff --git a/core/action_handler.js b/core/action_handler.js index 0a48b650a7..bd7afd68c1 100644 --- a/core/action_handler.js +++ b/core/action_handler.js @@ -6,7 +6,7 @@ module.exports = function container (get, set, clear) { var get_tick_str = get('utils.get_tick_str') var map = get('map') return function action_handler (tick, action, rs, cb) { - get('logger').info('action', get_tick_str(tick.id), action.type.grey) + get('logger').info('action', get_tick_str(tick.id), action.type.grey, action, {feed: 'actions'}) if (get('command') === 'run') { if (action.type === 'buy' || action.type === 'sell') { // @todo trade api diff --git a/core/indicators/rsi/_codemap.js b/core/indicators/rsi/_codemap.js index ac538d3ccd..f499d7dd5a 100644 --- a/core/indicators/rsi/_codemap.js +++ b/core/indicators/rsi/_codemap.js @@ -1,26 +1,7 @@ module.exports = { _ns: 'zenbrain', - 'mappers[]': require('./backfiller'), + 'mappers.rsi_backfiller': require('./backfiller'), + 'mappers[]': '#mappers.rsi_backfiller', 'reporter_cols.rsi': require('./reporter_col'), - 'tick_reducers[10]': require('./tick_reducer'), - '@commands.map': function container (get, set, clear) { - return function alter (command) { - command.options || (command.options = []) - command.options.push({ - name: 'backfill_rsi', - description: 'backfill RSI indicator (expensive)' - }) - return command - } - }, - '@commands.reduce': function container (get, set, clear) { - return function alter (command) { - command.options || (command.options = []) - command.options.push({ - name: 'backfill_rsi', - description: 'backfill RSI indicator (expensive)' - }) - return command - } - } + 'tick_reducers[10]': require('./tick_reducer') } \ No newline at end of file diff --git a/core/indicators/rsi/backfiller.js b/core/indicators/rsi/backfiller.js index b56e0dbb4d..153de3887e 100644 --- a/core/indicators/rsi/backfiller.js +++ b/core/indicators/rsi/backfiller.js @@ -10,7 +10,6 @@ module.exports = function container (get, set, clear) { var z = get('utils.zero_fill') return function mapper () { var options = get('options') - if (!options.backfill_rsi) return var min_time, num_marked = 0 function getNext () { var params = { @@ -47,10 +46,7 @@ module.exports = function container (get, set, clear) { setImmediate(getNext) } else { - get('logger').info('RSI', 'marked'.grey, num_marked, 'ticks for RSI backfill'.grey) - get('app').close(function () { - process.exit() - }) + get('logger').info('RSI', 'marked'.grey, num_marked, c.rsi_sizes.join(',') + ' ticks for RSI backfill'.grey) } }) } diff --git a/core/indicators/rsi/tick_reducer.js b/core/indicators/rsi/tick_reducer.js index 30c92450ad..12a29355a0 100644 --- a/core/indicators/rsi/tick_reducer.js +++ b/core/indicators/rsi/tick_reducer.js @@ -13,7 +13,7 @@ module.exports = function container (get, set, clear) { return function tick_reducer (g, cb) { var options = get('options') var tick = g.tick - if (c.rsi_sizes.indexOf(tick.size) === -1 || !tick.data.trades || (tick.time < start && !options.backfill_rsi)) return cb() + if (c.rsi_sizes.indexOf(tick.size) === -1 || !tick.data.trades) return cb() //console.error('computing RSI', tick.id) var bucket = tb(tick.time).resize(tick.size) var d = tick.data.trades diff --git a/default_logic.js b/default_logic.js new file mode 100644 index 0000000000..185ca46ccf --- /dev/null +++ b/default_logic.js @@ -0,0 +1,230 @@ +var first_run = true +var last_balance_sig + +module.exports = function container (get, set, clear) { + var c = get('config') + var o = get('utils.object_get') + var n = require('numbro') + var tb = require('timebucket') + var sig = require('sig') + var format_currency = get('utils.format_currency') + var get_timestamp = get('utils.get_timestamp') + var CoinbaseExchange = require('coinbase-exchange') + var client + var asset = 'BTC' + var currency = 'USD' + var rsi_period = '15m' + var rsi_overbought = 70 + var rsi_oversold = 20 + var check_period = '1m' + var exchange = 'gdax' + var selector = 'data.trades.' + exchange + '.' + asset + '-' + currency + var recovery_ticks = 300 + var trade_pct = 0.95 + var min_trade = 0.01 + function onOrder (err, resp, order) { + if (err) return get('logger').error('order err', err, resp, order, {feed: 'errors'}) + if (resp.statusCode !== 200) { + console.error(order) + return get('logger').error('non-200 status: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: order}}) + } + get('logger').info(exchange, ('order-id: ' + order.id).cyan, {data: {order: order}}) + function getStatus () { + client.getOrder(order.id, function (err, resp, order) { + if (err) return get('logger').error('getOrder err', err) + if (resp.statusCode !== 200) { + console.error(order) + return get('logger').error('non-200 status from getOrder: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: order}}) + } + if (order.status === 'done') { + return get('logger').info(exchange, ('order ' + order.id + ' done: ' + order.done_reason).cyan, {data: {order: order}}) + } + else { + get('logger').info(exchange, ('order ' + order.id + ' ' + order.status).cyan, {data: {order: order}}) + setTimeout(getStatus, 5000) + } + }) + } + getStatus() + } + return [ + // BEGIN DEFAULT TRADE LOGIC + // sync balance + function (tick, trigger, rs, cb) { + if (get('command') !== 'run' || !c.key) { + return cb() + } + if (!client) { + client = new CoinbaseExchange.AuthenticatedClient(c.key, c.secret, c.passphrase) + } + client.getAccounts(function (err, resp, accounts) { + if (err) throw err + if (resp.statusCode !== 200) { + console.error(accounts) + get('logger').error('non-200 status from exchange: ' + resp.statusCode, {data: {statusCode: resp.statusCode, body: accounts}}) + return cb && cb() + } + rs.balance = {} + accounts.forEach(function (account) { + if (account.currency === currency) { + rs.balance[currency] = n(account.balance).value() + } + else if (account.currency === asset) { + rs.balance[asset] = n(account.balance).value() + } + }) + var balance_sig = sig(rs.balance) + if (balance_sig !== last_balance_sig) { + get('logger').info(exchange, 'balance'.grey, n(rs.balance[asset]).format('0.000').white, asset.grey, n(rs.balance[currency]).format('0.00').yellow, currency.grey, {feed: 'exchange'}) + first_run = false + last_balance_sig = balance_sig + } + cb && cb() + }) + }, + function (tick, trigger, rs, cb) { + // note the last close price + var market_price = o(tick, selector + '.close') + if (market_price) { + rs.market_price = market_price + } + rs.ticks || (rs.ticks = 0) + rs.progress || (rs.progress = 0) + if (!rs.market_price) return cb() + if (!rs.balance) { + // start with $1000, neutral position + rs.balance = {} + rs.balance[currency] = 500 + rs.balance[asset] = n(500).divide(rs.market_price).value() + } + rs.ticks++ + if (tick.size !== check_period) { + // what % are we to a decision? + var base_time = tb(tick.time).resize(check_period).toMilliseconds() + var target_time = tb(tick.time).resize(check_period).add(1).toMilliseconds() + rs.progress = n(tick.time - base_time).divide(target_time - base_time).value() + return cb() + } + rs.progress = 1 + if (rs.recovery_ticks) { + rs.recovery_ticks-- + } + if (rs.recovery_ticks) { + return cb() + } + // check price diff + var close = o(tick || {}, selector + '.close') + // get rsi + var rsi_tick_id = tb(tick.time).resize(rsi_period).toString() + get('ticks').load(get('app_name') + ':' + rsi_tick_id, function (err, rsi_tick) { + if (err) return cb(err) + var rsi = o(rsi_tick || {}, selector + '.rsi') + var rsi_open = o(rsi_tick || {}, selector + '.open') + // require minimum data + // overbought/oversold + // sanity check + close || (close = o(rsi_tick || {}, selector + '.close')) + rs.check_diff = close ? n(close).subtract(rsi_open || close).value() : rs.check_diff || null + rs.last_close = close + if (!rsi) { + get('logger').info('trader', ('no ' + rsi_period + ' RSI').red, {feed: 'trader'}) + } + else if (rsi.samples < c.rsi_periods) { + get('logger').info('trader', (rsi_period + ' RSI: not enough samples: ' + rsi.samples).red, {feed: 'trader'}) + } + else if (!close) { + get('logger').info('trader', ('no close price').red, {feed: 'trader'}) + } + else if (rs.check_diff === null) { + get('logger').info('trader', ('not enough ticks to make decision').red, {feed: 'trader'}) + } + else { + rs.rsi = Math.round(rsi.value) + rs.rsi_ansi = rsi.ansi + if (rsi.value >= rsi_overbought && !rs.recovery_ticks) { + rs.overbought = true + } + else if (rsi.value <= rsi_oversold && !rs.recovery_ticks) { + rs.oversold = true + } + else { + get('logger').info('trader', (rsi_period + ' RSI: ').grey + rsi.ansi + ' diff: '.grey + format_currency(rs.check_diff, currency).grey, {feed: 'trader'}) + } + } + rs.recovery_ticks = recovery_ticks + 1 + cb() + }) + }, + // @todo MACD + function (tick, trigger, rs, cb) { + cb() + }, + // trigger trade signals + function (tick, trigger, rs, cb) { + if ((rs.overbought || rs.oversold) && rs.balance && rs.market_price) { + var size, new_balance = {} + if (rs.overbought) { + get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, 'anticipating a reversal DOWN. sell at market. (' + format_currency(rs.market_price, currency) + ') diff: ' + format_currency(rs.check_diff, currency), {feed: 'trader'}) + size = rs.balance[asset] + } + else if (rs.oversold) { + get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, 'anticipating a reversal UP. buy at market. (' + format_currency(rs.market_price, currency) + ') diff: ' + format_currency(rs.check_diff, currency), {feed: 'trader'}) + size = n(rs.balance[currency]).divide(rs.market_price).value() + } + // scale down size a little, to prevent out-of-balance errors + size = n(size || 0).multiply(trade_pct).value() + // min size + if (!size || size < min_trade) { + if (rs.overbought) { + //get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, ('not enough ' + asset + ' to execute sell!').red, {feed: 'trader'}) + } + else if (rs.oversold) { + //get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, ('not enough ' + currency + ' to execute buy!').red, {feed: 'trader'}) + } + rs.overbought = rs.oversold = false + return cb() + } + if (rs.overbought) { + new_balance[currency] = n(rs.balance[currency]).add(n(size).multiply(rs.market_price)).value() + new_balance[asset] = n(rs.balance[asset]).subtract(size).value() + } + else if (rs.oversold) { + new_balance[asset] = n(rs.balance[asset]).add(size).value() + new_balance[currency] = n(rs.balance[currency]).subtract(n(size).multiply(rs.market_price)).value() + } + // consolidate balance + var new_end_balance = n(new_balance[currency]).add(n(new_balance[asset]).multiply(rs.market_price)).value() + var new_roi = n(new_end_balance).divide(1000).value() + rs.balance = new_balance + rs.end_balance = new_end_balance + rs.roi = new_roi + rs.trades || (rs.trades = 0) + rs.trades++ + trigger({ + type: rs.overbought ? 'sell' : 'buy', + asset: asset, + currency: currency, + exchange: exchange, + price: rs.market_price, + market: true, + size: size, + rsi: rs.rsi, + roi: rs.roi + }) + if (get('command') === 'run' && c.key) { + var params = { + type: 'market', + size: n(size).format('0.000000'), + product_id: asset + '-' + currency + } + client[rs.overbought ? 'sell' : 'buy'](params, function (err, resp, order) { + onOrder(err, resp, order) + }) + } + rs.overbought = rs.oversold = false + } + cb() + } + // END DEFAULT TRADE LOGIC + ] +} \ No newline at end of file diff --git a/plugins/gdax/backfiller.js b/plugins/gdax/backfiller.js index 2299bc2a10..4e8fea4bf0 100644 --- a/plugins/gdax/backfiller.js +++ b/plugins/gdax/backfiller.js @@ -40,7 +40,7 @@ module.exports = function container (get, set, clear) { map('trade', obj) return obj }) - //log_trades(x.name, trades) + log_trades(x.name, trades) if (is_backfilled(trades)) { get('logger').info(x.name, (product.asset + '/' + product.currency + ' backfill complete').grey) } diff --git a/plugins/gdax/recorder.js b/plugins/gdax/recorder.js index fe6013086c..df3f98c4b5 100644 --- a/plugins/gdax/recorder.js +++ b/plugins/gdax/recorder.js @@ -38,7 +38,7 @@ module.exports = function container (get, set, clear) { map('trade', obj) return obj }) - //log_trades(x.name, trades) + log_trades(x.name, trades) retry() } var uri = x.rest_url + '/products/' + product.id + '/trades' + (s.recorder_id ? '?before=' + s.recorder_id : '') diff --git a/plugins/server/_codemap.js b/plugins/server/_codemap.js index 013c284ec0..eaed875327 100644 --- a/plugins/server/_codemap.js +++ b/plugins/server/_codemap.js @@ -12,7 +12,7 @@ module.exports = { return function task (cb) { if (get.exists('zenbrain:sim_result')) { var sim_result = get('zenbrain:sim_result') - console.error('simulation result graph: http://localhost:3013/?sim_id=' + sim_result.id) + console.error('simulation result graph: http://localhost:3013/?sim_id=' + sim_result.id + '&period=1h&limit=2000') } cb() } diff --git a/plugins/server/controllers/data.js b/plugins/server/controllers/data.js index de3eaa213d..24de3397ae 100644 --- a/plugins/server/controllers/data.js +++ b/plugins/server/controllers/data.js @@ -9,9 +9,6 @@ module.exports = function container (get, set) { .get('/sim_trades.csv', function (req, res, next) { res.setHeader('Content-Type', 'text/csv') res.write('Type,Time,Asset,Currency,Exchange,Price,Size,RSI,ROI\n') - if (!req.session.secret) { - return res.end() - } get('db.run_states').load(req.query.sim_id, function (err, sim_result) { if (err) return next(err) if (sim_result && sim_result.actions) { diff --git a/utils/is_backfilled.js b/utils/is_backfilled.js index 4f4a787922..9ba795214c 100644 --- a/utils/is_backfilled.js +++ b/utils/is_backfilled.js @@ -2,13 +2,18 @@ var tb = require('timebucket') module.exports = function container (get, set, clear) { var c = get('config') + var rsi_backfiller = get('mappers.rsi_backfiller') return function is_backfilled (trades) { if (!trades || !trades.length) return false var min_time = trades.reduce(function (prev, curr) { return prev ? Math.min(prev, curr.time) : curr.time }) - return min_time <= tb('1d') + var ret = min_time <= tb('1d') .subtract(c.backfill_days) .toMilliseconds() + if (ret) { + rsi_backfiller() + } + return ret } } \ No newline at end of file From 4985337d5c3fcaa32828d5cd45e41fe4803076de Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 15:37:17 -0700 Subject: [PATCH 24/56] update --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index c12a70a4c6..e41111ed95 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,10 @@ - Check out zenbot's [live feed!](https://zenbot.s8f.org/) - Join the discussion on [Reddit!](https://www.reddit.com/r/Bitcoin/comments/4xqo8q/announcing_zenbot_3_your_new_btcethltc_trading/)! +## Updates + +- **3.1.0** - Major logic update. Much of the default trade logic reprogrammed. Moved default logic to `./default_logic.js`. RSI now backfills by default, reconfigured to 15m intervals. Safe to drop your zenbrain DB before this update. + ## Description zenbot is an automated cryptocurrency trading bot. It runs on node.js and MongoDB and is fully open-sourced. A plugin architecture is included that allows any exchange, trade strategy, or currency pair to be supported. From e05fb57ebb62b3181d518842d8e045deda82db8c Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 15:37:20 -0700 Subject: [PATCH 25/56] 3.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1cb63075d8..397ad29a14 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zenbot_trader", - "version": "3.0.3", + "version": "3.1.0", "description": "A machine-learning cryptocurrency trading bot", "bin": { "zenbot": "./zenbot" From 624588fb4f73de297e2d519f2ae7300c876d6980 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 15:39:28 -0700 Subject: [PATCH 26/56] update zenbrain version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 397ad29a14..f6bfdffc67 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "sig": "^1.0.0", "timebucket": "^0.3.4", "twit": "^2.2.4", - "zenbrain": "git+https://github.com/carlos8f/zenbrain.git#d90d42ae9c07ef6ad50a04c2fe9ecfae4a026e01", + "zenbrain": "git+https://github.com/carlos8f/zenbrain.git#e3d5b6430da645f44a420007fb90d34753ee67cf", "zero-fill": "^2.2.3" } } From 0bf9e80072562540e8d28fd2357d9220666b11f9 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 15:39:31 -0700 Subject: [PATCH 27/56] 3.1.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f6bfdffc67..c1a84a8e83 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zenbot_trader", - "version": "3.1.0", + "version": "3.1.1", "description": "A machine-learning cryptocurrency trading bot", "bin": { "zenbot": "./zenbot" From 9db1222308b6fea3a5058d6661290f0423c7e60a Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 15:40:02 -0700 Subject: [PATCH 28/56] note update --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e41111ed95..38b34373d7 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ ## Updates +- **3.1.1** - Updated zenbrain version. + - **3.1.0** - Major logic update. Much of the default trade logic reprogrammed. Moved default logic to `./default_logic.js`. RSI now backfills by default, reconfigured to 15m intervals. Safe to drop your zenbrain DB before this update. ## Description From cd15fd6b5894b2550a3613b4a72d30fb6f806d41 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 15:40:36 -0700 Subject: [PATCH 29/56] note --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 38b34373d7..53f3188686 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ ## Updates -- **3.1.1** - Updated zenbrain version. +- **3.1.1** - Updated zenbrain version. Please run `./update.sh`. - **3.1.0** - Major logic update. Much of the default trade logic reprogrammed. Moved default logic to `./default_logic.js`. RSI now backfills by default, reconfigured to 15m intervals. Safe to drop your zenbrain DB before this update. From 4b463ab9ee80c5d622b74f69f400ccddc675b57c Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 15:47:02 -0700 Subject: [PATCH 30/56] relax backfill timeout --- config.js | 2 +- plugins/gdax/exchange.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config.js b/config.js index f2085a53a3..41870471d5 100644 --- a/config.js +++ b/config.js @@ -83,7 +83,7 @@ c.trade_report_interval = 5000 // backfiller c.backfill_days = 91 c.record_timeout = 20000 -c.backfill_timeout = 500 +c.backfill_timeout = 5000 // simulator c.sim_input_unit = "7d" diff --git a/plugins/gdax/exchange.json b/plugins/gdax/exchange.json index 0ffa65f0b2..d6a704bc4d 100644 --- a/plugins/gdax/exchange.json +++ b/plugins/gdax/exchange.json @@ -2,7 +2,7 @@ "name": "gdax", "rest_url": "https://api.gdax.com", "backfill_limit": 100, - "backfill_timeout": 0, + "backfill_timeout": 1000, "products": [ { "id":"BTC-USD", From a1f80950ef6978f7aaf182c303489fa280a4af09 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 15:49:06 -0700 Subject: [PATCH 31/56] report intervals --- README.md | 2 ++ config.js | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 53f3188686..c494f07abc 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ ## Updates +- **3.1.2** - Relaxed backfill timeout. Backfill is slower to let reducer catch up. Reducer report interval -> 30s, Trade report interval -> 30s + - **3.1.1** - Updated zenbrain version. Please run `./update.sh`. - **3.1.0** - Major logic update. Much of the default trade logic reprogrammed. Moved default logic to `./default_logic.js`. RSI now backfills by default, reconfigured to 15m intervals. Safe to drop your zenbrain DB before this update. diff --git a/config.js b/config.js index 41870471d5..61cfd907e4 100644 --- a/config.js +++ b/config.js @@ -77,8 +77,8 @@ c.reporter_cols = [ "price", //"progress" ] -c.reducer_report_interval = 5000 -c.trade_report_interval = 5000 +c.reducer_report_interval = 30000 +c.trade_report_interval = 30000 // backfiller c.backfill_days = 91 From 5c61c0562fdd841f94986f4950b465d284fa9132 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 15:49:10 -0700 Subject: [PATCH 32/56] 3.1.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c1a84a8e83..c45b71ffb6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zenbot_trader", - "version": "3.1.1", + "version": "3.1.2", "description": "A machine-learning cryptocurrency trading bot", "bin": { "zenbot": "./zenbot" From b7a04a2aa7323685718b8a41b8e91ec4801df2cb Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 16:10:40 -0700 Subject: [PATCH 33/56] update trade logic description --- README.md | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index c494f07abc..a19e127b9b 100644 --- a/README.md +++ b/README.md @@ -89,25 +89,27 @@ zenbot sim Zenbot will return you a list of virtual trades, and an ROI figure. Open the URL provided in the console (while running the server) to see the virtual trades plotted on a candlestick graph. Tweak `config.js` for new trade strategies and check your results this way. -### 7. Web console - -When the server is running, and you have visited the `?secret` URL provided in the console, you can access an aggregated, live feed of log messages at `http://localhost:3013/logs`. Example: - -![screenshot](https://raw.githubusercontent.com/carlos8f/zenbot/master/assets/zenbot_web_logs.png) - -## About the default trade logic in config.js +#### About the default trade logic in `default_logic.js` - uses [GDAX](https://gdax.com/) API - watches/trades BTC/USD -- acts at 6h increments (ticks), but you can configure to act quicker or slower. -- computes 14-period 6h RSI -- considers `RSI > 70` overbought and `RSI < 30` oversold +- acts at 1m increments (ticks), but you can configure to act quicker or slower. +- computes 14-period 15m RSI +- considers `RSI >= 70` overbought and `RSI <= 20` oversold - trades 95% of current balance, market price -You can tweak `config.js` from there to use bitfinex, or trade ETH, or whatever. Common `config.js` logic will be moved to core or plugins in later versions of zenbot. Use `zenbot sim` to check your trade strategy against historical trades. +You can tweak `config.js` from there to use bitfinex, or trade ETH, or whatever. After tweaking `default_logic.js`, Use `zenbot sim` to check your strategy against historical trades. + +Note that simulations always end on Wednesday 5pm PST, and run for a max 90 days, to ensure consistency of results. Auto-learn support and more exchange support will come soon. Will accept PR's :) With the 3.x plugin architecture, external plugins are possible too (published as their own repo/module). +### 7. Web console + +When the server is running, and you have visited the `?secret` URL provided in the console, you can access an aggregated, live feed of log messages at `http://localhost:3013/logs`. Example: + +![screenshot](https://raw.githubusercontent.com/carlos8f/zenbot/master/assets/zenbot_web_logs.png) + ## FAQ ### Can I use zenbot with [X] exchange? From a3e8a67fd519f3d7d04302fe935768835fbd7ce4 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 16:15:46 -0700 Subject: [PATCH 34/56] verbose flag --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a19e127b9b..2578a5e363 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ The `./run.sh` script combines `launch map --backfill reduce run server`, so use Once backfill has finished, run a simulation: ```shell -zenbot sim +zenbot sim [--verbose] ``` Zenbot will return you a list of virtual trades, and an ROI figure. Open the URL provided in the console (while running the server) to see the virtual trades plotted on a candlestick graph. Tweak `config.js` for new trade strategies and check your results this way. From 37613d17b8f3f6c4e3ad4cb053e3d47ce6ad3005 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 16:16:57 -0700 Subject: [PATCH 35/56] doc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2578a5e363..737274967a 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ Zenbot will return you a list of virtual trades, and an ROI figure. Open the URL - considers `RSI >= 70` overbought and `RSI <= 20` oversold - trades 95% of current balance, market price -You can tweak `config.js` from there to use bitfinex, or trade ETH, or whatever. After tweaking `default_logic.js`, Use `zenbot sim` to check your strategy against historical trades. +You can tweak the JS from there to use bitfinex, or trade ETH, or whatever. After tweaking `default_logic.js`, Use `zenbot sim` to check your strategy against historical trades. Note that simulations always end on Wednesday 5pm PST, and run for a max 90 days, to ensure consistency of results. From 1cd00cd1ef35442613899d661085b11747d9f3df Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 16:21:31 -0700 Subject: [PATCH 36/56] btc --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 737274967a..ab5e1251bc 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,15 @@ Source: [Wikipedia](https://en.wikipedia.org/wiki/Technical_analysis#Systematic_ ## Donate -P.S., some have asked for how to donate to Zenbot development. I accept donations at [my Bitcoin address](bitcoin:187rmNSkSvehgcKpBunre6a5wA5hQQop6W), thanks! +P.S., some have asked for how to donate to Zenbot development. I accept donations at **my Bitcoin address** Here: + +### carlos8f's BTC + +`187rmNSkSvehgcKpBunre6a5wA5hQQop6W` + +![zenbot logo](https://s8f.org/files/bitcoin.png) + +thanks! ## Discuss From 9e9aeac138b96bff64c3e5744d2bd7688544ead6 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 16:45:58 -0700 Subject: [PATCH 37/56] new graph defaults --- config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config.js b/config.js index 61cfd907e4..131091984b 100644 --- a/config.js +++ b/config.js @@ -35,8 +35,8 @@ c.twitter_access_token = "" c.twitter_access_token_secret = "" // graph server -c.default_graph_period = "1h" -c.default_graph_limit = 300 +c.default_graph_period = "15m" +c.default_graph_limit = 1000 c.graph_limits = [50, 100, 150, 200, 300, 500, 1000, 2000] c.graph_selectors = [ "gdax.BTC-USD", From 367a57417b2cf6788c29e037088436337182f143 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 17:09:03 -0700 Subject: [PATCH 38/56] add progress to default reporter --- config.js | 2 +- default_logic.js | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/config.js b/config.js index 131091984b..334116694f 100644 --- a/config.js +++ b/config.js @@ -75,7 +75,7 @@ c.reporter_cols = [ "rsi", "volume", "price", - //"progress" + "progress" ] c.reducer_report_interval = 30000 c.trade_report_interval = 30000 diff --git a/default_logic.js b/default_logic.js index 185ca46ccf..f6326547e1 100644 --- a/default_logic.js +++ b/default_logic.js @@ -99,16 +99,14 @@ module.exports = function container (get, set, clear) { } rs.ticks++ if (tick.size !== check_period) { - // what % are we to a decision? - var base_time = tb(tick.time).resize(check_period).toMilliseconds() - var target_time = tb(tick.time).resize(check_period).add(1).toMilliseconds() - rs.progress = n(tick.time - base_time).divide(target_time - base_time).value() return cb() } rs.progress = 1 if (rs.recovery_ticks) { rs.recovery_ticks-- } + // what % are we to a decision? + rs.progress = recovery_ticks ? n(1).subtract(n(rs.recovery_ticks).divide(recovery_ticks)).value() : 1 if (rs.recovery_ticks) { return cb() } From 3fc13c549a61809226cfa74a4dfc12ed32aa04e5 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 20:02:19 -0700 Subject: [PATCH 39/56] fix license double --- README.md | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/README.md b/README.md index ab5e1251bc..3a4c61b8f4 100644 --- a/README.md +++ b/README.md @@ -181,30 +181,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -- - - - -### License: MIT - -- Copyright (C) 2016 Carlos Rodriguez (http://s8f.org/) -- Copyright (C) 2016 Terra Eclipse, Inc. (http://www.terraeclipse.com/) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished -to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - From 8e54d1fc1f199653015c6e5f22440e05c9a7fcda Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 20:12:30 -0700 Subject: [PATCH 40/56] no shell lexer --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3a4c61b8f4..b93beca68a 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ HOWEVER. BE AWARE that once you hook up zenbot to a live exchange, the damage do ### 2. Install zenbot 3: -```shell +``` git clone https://github.com/carlos8f/zenbot.git cd zenbot npm install @@ -49,7 +49,7 @@ npm install ### 4. Run zenbot on the exchange: -```shell +``` ./run.sh ``` @@ -57,7 +57,7 @@ npm install To access the CLI, -```shell +``` zenbot Usage: zenbot [options] [command] @@ -83,7 +83,7 @@ The `./run.sh` script combines `launch map --backfill reduce run server`, so use Once backfill has finished, run a simulation: -```shell +``` zenbot sim [--verbose] ``` From 55ffa5170a75bbe6e019bf9f8cb1562a1aefddf5 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 22:52:42 -0700 Subject: [PATCH 41/56] no windows --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index b93beca68a..00edaee492 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,12 @@ HOWEVER. BE AWARE that once you hook up zenbot to a live exchange, the damage do ### 1. Requirements: [Node.js](https://nodejs.org/) and [MongoDB](https://www.mongodb.com/download-center) +### 2.5 Windows - I don't support it. + +If you're having an error on Windows and you're about to give up, it's probaby because Node.js is generally broken on Windows and you should try running on a Linux docker container or a Mac instead. + +If you're still insistent on using Windows, you'll have to fork zenbot, fix it yourself, and I'll accept a Pull Request. + ### 2. Install zenbot 3: ``` From c5e41647f6178bf97091f23eb34871eda02347b6 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 22:54:07 -0700 Subject: [PATCH 42/56] windows --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 00edaee492..ce2695cae2 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ HOWEVER. BE AWARE that once you hook up zenbot to a live exchange, the damage do ### 1. Requirements: [Node.js](https://nodejs.org/) and [MongoDB](https://www.mongodb.com/download-center) -### 2.5 Windows - I don't support it. +#### Windows - I don't support it. If you're having an error on Windows and you're about to give up, it's probaby because Node.js is generally broken on Windows and you should try running on a Linux docker container or a Mac instead. From 764f49d6ee2c306cde3e0de057e3f4a68192bc48 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 15 Aug 2016 23:53:48 -0700 Subject: [PATCH 43/56] example sim --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ce2695cae2..2d939532ea 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,8 @@ zenbot sim [--verbose] Zenbot will return you a list of virtual trades, and an ROI figure. Open the URL provided in the console (while running the server) to see the virtual trades plotted on a candlestick graph. Tweak `config.js` for new trade strategies and check your results this way. +Example simulation graph: https://zenbot.s8f.org/?sim_id=9cb6ac63f85168e3&period=1h&limit=2000 + #### About the default trade logic in `default_logic.js` - uses [GDAX](https://gdax.com/) API From 2326fa6da90d1375a7c7984292f6563a54e18c96 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 16 Aug 2016 00:03:23 -0700 Subject: [PATCH 44/56] better url --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2d939532ea..e4036173e7 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ zenbot sim [--verbose] Zenbot will return you a list of virtual trades, and an ROI figure. Open the URL provided in the console (while running the server) to see the virtual trades plotted on a candlestick graph. Tweak `config.js` for new trade strategies and check your results this way. -Example simulation graph: https://zenbot.s8f.org/?sim_id=9cb6ac63f85168e3&period=1h&limit=2000 +Example simulation graph: https://zenbot.s8f.org/?sim_id=9cb6ac63f85168e3&selector=gdax.BTC-USD&period=6h&limit=2000 #### About the default trade logic in `default_logic.js` From ea3bdedf115af3e9d3b7e8e9cd76b572ad55b38a Mon Sep 17 00:00:00 2001 From: Luigi Maselli Date: Tue, 16 Aug 2016 12:19:16 +0200 Subject: [PATCH 45/56] initial kraken support --- plugins/kraken/_codemap.js | 9 ++++ plugins/kraken/backfiller.js | 79 +++++++++++++++++++++++++++++++++++- plugins/kraken/exchange.json | 18 +++++++- 3 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 plugins/kraken/_codemap.js diff --git a/plugins/kraken/_codemap.js b/plugins/kraken/_codemap.js new file mode 100644 index 0000000000..0a763544d6 --- /dev/null +++ b/plugins/kraken/_codemap.js @@ -0,0 +1,9 @@ +module.exports = { + _ns: 'zenbrain', + 'exchanges.kraken': require('./exchange.json'), + 'exchanges[]': '#exchanges.kraken', + 'mappers[]': [ + require('./backfiller') //, + //require('./recorder') + ] +} diff --git a/plugins/kraken/backfiller.js b/plugins/kraken/backfiller.js index 3e14233570..50d3e12b53 100644 --- a/plugins/kraken/backfiller.js +++ b/plugins/kraken/backfiller.js @@ -1,3 +1,78 @@ -https://www.kraken.com/help/api -https://api.kraken.com/0/public/Trades?pair=XBTUSD \ No newline at end of file +// https://www.kraken.com/help/api +// https://api.kraken.com/0/public/Trades?pair=XBTUSD + +var request = require('micro-request') + , n = require('numbro') + +module.exports = function container (get, set, clear) { + var x = get('exchanges.kraken') + var c = get('config') + var log_trades = get('utils.log_trades') + var get_products = get('utils.get_products') + var is_backfilled = get('utils.is_backfilled') + var map = get('map') + return function mapper () { + var products = get_products(x) + var options = get('options') + if (!options.backfill || !products.length) return + var rs = get('run_state') + rs[x.name] || (rs[x.name] = {}) + rs = rs[x.name] + products.forEach(function (product) { + rs[product.id] || (rs[product.id] = {}) + var s = rs[product.id] + //s.backfiller_id = null // start from scratch + function retry () { + setTimeout(getNext, x.backfill_timeout) + } + function getNext () { + function withResult (result) { + var trades = result.map(function (trade) { + s.backfiller_id = s.backfiller_id ? Math.min(s.backfiller_id, trade.trade_id) : trade.trade_id + var obj = { + id: x.name + '-' + String(trade.trade_id), + trade_id: trade.trade_id, + time: new Date(trade.time).getTime(), + asset: product.asset, + currency: product.currency, + size: n(trade.size).value(), + price: n(trade.price).value(), + side: trade.side, + exchange: x.name + } + map('trade', obj) + return obj + }) + log_trades(x.name, trades) + if (is_backfilled(trades)) { + get('logger').info(x.name, (product.asset + '/' + product.currency + ' backfill complete').grey) + } + else { + retry() + } + } + var uri = x.rest_url + '/public/Trades?pair=' + product.id + '&limit=' + x.backfill_limit + (s.backfiller_id ? '&since=' + s.backfiller_id : '') + //comment + //get('logger').info(z(c.max_slug_length, 'backfiller GET', ' '), uri.grey) + get('logger').info("HERE", uri) + request(uri, {headers: {'User-Agent': USER_AGENT}}, function (err, resp, result) { + if (err) { + get('logger').error(x.name + ' backfiller err', err, {feed: 'errors'}) + return retry() + } + if (resp.statusCode !== 200 /* || toString.call(result) !== '[object Array]' */ ) { + console.error(result) + get('logger').error(x.name + ' non-200 status: ' + resp.statusCode, {feed: 'errors'}) + return retry() + } + + get('logger').info("KRAKEN data", result.result.XXBTZUSD) + + withResult(result.result.XXBTZUSD[0]) + }) + } + getNext() + }) + } +} diff --git a/plugins/kraken/exchange.json b/plugins/kraken/exchange.json index 99e445b5ea..1a80b20570 100644 --- a/plugins/kraken/exchange.json +++ b/plugins/kraken/exchange.json @@ -1 +1,17 @@ -exchange.json \ No newline at end of file +{ + "name": "kraken", + "rest_url": "https://api.kraken.com/0", + "backfill_limit": 100, + "backfill_timeout": 1000, + "products": [ + { + "id":"XBTUSD", + "asset":"BTC", + "currency":"USD", + "min_size":0.01, + "max_size":10000, + "increment":0.01, + "label":"BTC/USD" + } + ] +} From 44aff8a914dfc60c6ff0949e95192a91386f40d3 Mon Sep 17 00:00:00 2001 From: xangma Date: Tue, 16 Aug 2016 12:20:06 +0100 Subject: [PATCH 46/56] ROI calc fix Moved the constant $1000 balance var to top so it can be changed, fixed ROI calc --- default_logic.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/default_logic.js b/default_logic.js index f6326547e1..a47b760f80 100644 --- a/default_logic.js +++ b/default_logic.js @@ -22,6 +22,7 @@ module.exports = function container (get, set, clear) { var recovery_ticks = 300 var trade_pct = 0.95 var min_trade = 0.01 + var tot_balance = 1000 function onOrder (err, resp, order) { if (err) return get('logger').error('order err', err, resp, order, {feed: 'errors'}) if (resp.statusCode !== 200) { @@ -92,10 +93,10 @@ module.exports = function container (get, set, clear) { rs.progress || (rs.progress = 0) if (!rs.market_price) return cb() if (!rs.balance) { - // start with $1000, neutral position + // start with tot_balance, neutral position rs.balance = {} - rs.balance[currency] = 500 - rs.balance[asset] = n(500).divide(rs.market_price).value() + rs.balance[currency] = tot_balance/2 + rs.balance[asset] = n(tot_balance/2).divide(rs.market_price).value() } rs.ticks++ if (tick.size !== check_period) { @@ -192,7 +193,7 @@ module.exports = function container (get, set, clear) { } // consolidate balance var new_end_balance = n(new_balance[currency]).add(n(new_balance[asset]).multiply(rs.market_price)).value() - var new_roi = n(new_end_balance).divide(1000).value() + var new_roi = n(new_end_balance).divide(tot_balance).value() rs.balance = new_balance rs.end_balance = new_end_balance rs.roi = new_roi @@ -225,4 +226,4 @@ module.exports = function container (get, set, clear) { } // END DEFAULT TRADE LOGIC ] -} \ No newline at end of file +} From 5d7e54479931db173d1f1bd386e63f017173e055 Mon Sep 17 00:00:00 2001 From: xangma Date: Tue, 16 Aug 2016 12:43:07 +0100 Subject: [PATCH 47/56] Update default_logic.js --- default_logic.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/default_logic.js b/default_logic.js index a47b760f80..db9f210526 100644 --- a/default_logic.js +++ b/default_logic.js @@ -22,7 +22,7 @@ module.exports = function container (get, set, clear) { var recovery_ticks = 300 var trade_pct = 0.95 var min_trade = 0.01 - var tot_balance = 1000 + var start_balance = 1000 function onOrder (err, resp, order) { if (err) return get('logger').error('order err', err, resp, order, {feed: 'errors'}) if (resp.statusCode !== 200) { @@ -93,10 +93,10 @@ module.exports = function container (get, set, clear) { rs.progress || (rs.progress = 0) if (!rs.market_price) return cb() if (!rs.balance) { - // start with tot_balance, neutral position + // start with start_balance, neutral position rs.balance = {} - rs.balance[currency] = tot_balance/2 - rs.balance[asset] = n(tot_balance/2).divide(rs.market_price).value() + rs.balance[currency] = start_balance/2 + rs.balance[asset] = n(start_balance/2).divide(rs.market_price).value() } rs.ticks++ if (tick.size !== check_period) { @@ -193,7 +193,7 @@ module.exports = function container (get, set, clear) { } // consolidate balance var new_end_balance = n(new_balance[currency]).add(n(new_balance[asset]).multiply(rs.market_price)).value() - var new_roi = n(new_end_balance).divide(tot_balance).value() + var new_roi = n(new_end_balance).divide(start_balance).value() rs.balance = new_balance rs.end_balance = new_end_balance rs.roi = new_roi From a4d74cd90e375a62e77b86c63d5e5bf8fa2bcfde Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 16 Aug 2016 09:50:08 -0700 Subject: [PATCH 48/56] bring back "not enough asset/currency messages --- default_logic.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/default_logic.js b/default_logic.js index f6326547e1..c7d70e51de 100644 --- a/default_logic.js +++ b/default_logic.js @@ -174,10 +174,10 @@ module.exports = function container (get, set, clear) { // min size if (!size || size < min_trade) { if (rs.overbought) { - //get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, ('not enough ' + asset + ' to execute sell!').red, {feed: 'trader'}) + get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, ('not enough ' + asset + ' to execute sell!').red, {feed: 'trader'}) } else if (rs.oversold) { - //get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, ('not enough ' + currency + ' to execute buy!').red, {feed: 'trader'}) + get('logger').info('trader', 'RSI:'.grey + rs.rsi_ansi, ('not enough ' + currency + ' to execute buy!').red, {feed: 'trader'}) } rs.overbought = rs.oversold = false return cb() From e640e55f753cc5d1588007f5ecc7511ba25f5678 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 16 Aug 2016 09:54:45 -0700 Subject: [PATCH 49/56] rsi backfill honors backfill option --- core/indicators/rsi/backfiller.js | 1 + 1 file changed, 1 insertion(+) diff --git a/core/indicators/rsi/backfiller.js b/core/indicators/rsi/backfiller.js index 153de3887e..ab41b5b5ec 100644 --- a/core/indicators/rsi/backfiller.js +++ b/core/indicators/rsi/backfiller.js @@ -10,6 +10,7 @@ module.exports = function container (get, set, clear) { var z = get('utils.zero_fill') return function mapper () { var options = get('options') + if (!options.backfill) return var min_time, num_marked = 0 function getNext () { var params = { From a2326cf5cfaa51583126efd6363366ca49c45e46 Mon Sep 17 00:00:00 2001 From: Luigi Maselli Date: Tue, 16 Aug 2016 19:00:01 +0200 Subject: [PATCH 50/56] WIP should work backfilling --- plugins/kraken/_codemap.js | 4 +- plugins/kraken/backfiller.js | 54 +++++++++++++------ plugins/kraken/recorder.js | 101 ++++++++++++++++++++++++++++++++++- 3 files changed, 140 insertions(+), 19 deletions(-) diff --git a/plugins/kraken/_codemap.js b/plugins/kraken/_codemap.js index 0a763544d6..a08f834ec3 100644 --- a/plugins/kraken/_codemap.js +++ b/plugins/kraken/_codemap.js @@ -3,7 +3,7 @@ module.exports = { 'exchanges.kraken': require('./exchange.json'), 'exchanges[]': '#exchanges.kraken', 'mappers[]': [ - require('./backfiller') //, - //require('./recorder') + require('./backfiller'), + require('./recorder') ] } diff --git a/plugins/kraken/backfiller.js b/plugins/kraken/backfiller.js index 50d3e12b53..3af6c8c215 100644 --- a/plugins/kraken/backfiller.js +++ b/plugins/kraken/backfiller.js @@ -1,7 +1,17 @@ // https://www.kraken.com/help/api // https://api.kraken.com/0/public/Trades?pair=XBTUSD - +/* +id: 'gdax-8809631', + trade_id: 8809631, + time: 1464316978837, + asset: 'BTC', + currency: 'USD', + size: 0.01470572, + price: 467.45, + side: 'sell', + exchange: 'gdax' } +*/ var request = require('micro-request') , n = require('numbro') @@ -28,19 +38,31 @@ module.exports = function container (get, set, clear) { } function getNext () { function withResult (result) { + // , ,