From eb30a7b33c29edc5d30b8cd354204cc1170b11f3 Mon Sep 17 00:00:00 2001 From: Klemens Wittig Date: Tue, 28 Aug 2018 15:12:13 +0200 Subject: [PATCH 1/8] Include STDDEV in tulind.js add missing stddev --- core/tulind.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core/tulind.js b/core/tulind.js index 04b6766ff..bd40a1c09 100644 --- a/core/tulind.js +++ b/core/tulind.js @@ -704,6 +704,20 @@ methods.sma = { } } +methods.stddev = { + requires: ['optInTimePeriod'], + create: (params) => { + verifyParams('stddev', params); + + return (data, callback) => execute(callback, { + indicator: tulind.indicators.stddev, + inputs: [data.close], + options: [params.optInTimePeriod], + results: ['result'], + }); + } +} + methods.stoch = { requires: ['optInFastKPeriod', 'optInSlowKPeriod', 'optInSlowDPeriod'], create: (params) => { From 60b6eb87d2a4b4dccd398087f484d66b392f93bc Mon Sep 17 00:00:00 2001 From: Mike van Rossum Date: Tue, 28 Aug 2018 16:45:50 +0800 Subject: [PATCH 2/8] make sure to flush the batcher, fix #2329 --- core/tools/dataStitcher.js | 1 + plugins/tradingAdvisor/tradingAdvisor.js | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/tools/dataStitcher.js b/core/tools/dataStitcher.js index 1431cf1d7..252ef93ae 100644 --- a/core/tools/dataStitcher.js +++ b/core/tools/dataStitcher.js @@ -223,6 +223,7 @@ Stitcher.prototype.seedLocalData = function(from, to, next) { }); this.batcher.write(rows); + this.batcher.flush(); this.reader.close(); next(); diff --git a/plugins/tradingAdvisor/tradingAdvisor.js b/plugins/tradingAdvisor/tradingAdvisor.js index a981bb282..e6de3a054 100644 --- a/plugins/tradingAdvisor/tradingAdvisor.js +++ b/plugins/tradingAdvisor/tradingAdvisor.js @@ -92,14 +92,15 @@ Actor.prototype.processCandle = function(candle, done) { this.next = done; } else { done(); - this.next = _.noop; + this.next = false; } this.batcher.flush(); } // propogate a custom sized candle to the trading strategy Actor.prototype.emitStratCandle = function(candle) { - this.strategy.tick(candle, this.next); + const next = this.next || _.noop; + this.strategy.tick(candle, next); } Actor.prototype.processTradeCompleted = function(trade) { From 1dd3e10b3b4cc814ba610d0f2f36eefbc1b06249 Mon Sep 17 00:00:00 2001 From: Mike van Rossum Date: Wed, 29 Aug 2018 16:06:31 +0800 Subject: [PATCH 3/8] [GB] catch EAI_AGAIN DNS error --- exchange/wrappers/coinfalcon.js | 4 +++- exchange/wrappers/gdax.js | 3 ++- exchange/wrappers/poloniex.js | 4 +++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/exchange/wrappers/coinfalcon.js b/exchange/wrappers/coinfalcon.js index df49ce1db..f85d2341a 100644 --- a/exchange/wrappers/coinfalcon.js +++ b/exchange/wrappers/coinfalcon.js @@ -57,7 +57,9 @@ const recoverableErrors = [ // https://github.com/askmike/gekko/issues/2407 'We are fixing a few issues, be back shortly.', 'Client network socket disconnected before secure TLS connection was established', - 'socket hang up' + 'socket hang up', + // getaddrinfo EAI_AGAIN coinfalcon.com coinfalcon.com:443 + 'EAI_AGAIN' ]; Trader.prototype.processResponse = function(method, args, next) { diff --git a/exchange/wrappers/gdax.js b/exchange/wrappers/gdax.js index a5a15227e..a5ad0f061 100644 --- a/exchange/wrappers/gdax.js +++ b/exchange/wrappers/gdax.js @@ -60,7 +60,8 @@ const recoverableErrors = [ 'HTTP 504 Error', 'HTTP 503 Error', 'socket hang up', - 'EHOSTUNREACH' + 'EHOSTUNREACH', + 'EAI_AGAIN' ]; const includes = (str, list) => { diff --git a/exchange/wrappers/poloniex.js b/exchange/wrappers/poloniex.js index 8a6f89c2d..d10b2e183 100644 --- a/exchange/wrappers/poloniex.js +++ b/exchange/wrappers/poloniex.js @@ -42,7 +42,9 @@ const recoverableErrors = [ 'Please try again in a few minutes.', 'Nonce must be greater than', 'Internal error. Please try again.', - 'Connection timed out. Please try again.' + 'Connection timed out. Please try again.', + // getaddrinfo EAI_AGAIN poloniex.com poloniex.com:443 + 'EAI_AGAIN' ]; // errors that might mean From c5f4f81977447226eab020b213516d5e959e5b07 Mon Sep 17 00:00:00 2001 From: Mike van Rossum Date: Wed, 29 Aug 2018 18:00:18 +0800 Subject: [PATCH 4/8] persist new direction after completing stop --- plugins/tradingAdvisor/baseTradingMethod.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/plugins/tradingAdvisor/baseTradingMethod.js b/plugins/tradingAdvisor/baseTradingMethod.js index 96efa4097..58be93692 100644 --- a/plugins/tradingAdvisor/baseTradingMethod.js +++ b/plugins/tradingAdvisor/baseTradingMethod.js @@ -188,6 +188,17 @@ Base.prototype.propogateTick = function(candle) { } Base.prototype.processTrade = function(trade) { + if( + this._pendingTriggerAdvice && + trade.action === 'sell' && + this._pendingTriggerAdvice === trade.adviceId + ) { + // This trade came from a trigger of the previous advice, + // update stored direction + this._currentDirection = 'short'; + this._pendingTriggerAdvice = null; + } + this.onTrade(trade); } @@ -224,6 +235,10 @@ Base.prototype.advice = function(newDirection) { return; } + if(newDirection.direction === this._currentDirection) { + return; + } + if(_.isObject(newDirection.trigger)) { if(newDirection.direction !== 'long') { log.warn( @@ -260,6 +275,9 @@ Base.prototype.advice = function(newDirection) { if(trigger) { advice.trigger = trigger; + this._pendingTriggerAdvice = 'advice-' + this.propogatedAdvices; + } else { + this._pendingTriggerAdvice = null; } this.emit('advice', advice); From f4786faddacdfe06d85315daa9672dd2879eb934 Mon Sep 17 00:00:00 2001 From: Mike van Rossum Date: Thu, 30 Aug 2018 14:11:42 +0800 Subject: [PATCH 5/8] unref pending trigger if the strategy shorts --- plugins/tradingAdvisor/baseTradingMethod.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/tradingAdvisor/baseTradingMethod.js b/plugins/tradingAdvisor/baseTradingMethod.js index 58be93692..766be4380 100644 --- a/plugins/tradingAdvisor/baseTradingMethod.js +++ b/plugins/tradingAdvisor/baseTradingMethod.js @@ -264,6 +264,10 @@ Base.prototype.advice = function(newDirection) { return; } + if(newDirection === 'short' && this._pendingTriggerAdvice) { + this._pendingTriggerAdvice = null; + } + this._currentDirection = newDirection; this.propogatedAdvices++; From 81462e3d334e2158f027db70e07458589983d9f2 Mon Sep 17 00:00:00 2001 From: Mike van Rossum Date: Fri, 31 Aug 2018 13:42:38 +0800 Subject: [PATCH 6/8] [DOCS] add youtube vid with strategy tutorial --- docs/strategies/creating_a_strategy.md | 4 ++-- docs/strategies/introduction.md | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/strategies/creating_a_strategy.md b/docs/strategies/creating_a_strategy.md index 635bfbeba..188b273ad 100644 --- a/docs/strategies/creating_a_strategy.md +++ b/docs/strategies/creating_a_strategy.md @@ -2,9 +2,9 @@ Strategies are the core of Gekko's trading bot. They look at the market and decide what to do based on technical analysis indicators. A single strategy is limited to a single market on a single exchange. -Gekko currently comes with [a couple of strategies](./introduction.md) out of the box. Besides those you can also write your own strategy in javascript. The easiest way to do this is to customize the file `gekko/strategies/custom.js`. +Gekko currently comes with [a couple of strategies](./introduction.md) out of the box. Besides those you can also write your own strategy in javascript. If you want to understand how to create your own strategy you can watch this video or read the tech docs on this page. -## Creating a strategy +[![youtube video on how to create gekko strategies](https://gekko.wizb.it/_static/create-strat-vid.jpg)](https://www.youtube.com/watch?v=6-74ZhrG0BE) A strategy is a module with a few functions that get market data in the form of candles ([OHLC](https://en.wikipedia.org/wiki/Open-high-low-close_chart), volume, and the average weighted price) and output trading advice. diff --git a/docs/strategies/introduction.md b/docs/strategies/introduction.md index edb5b5d7f..ef379a9c6 100644 --- a/docs/strategies/introduction.md +++ b/docs/strategies/introduction.md @@ -4,7 +4,11 @@ Gekko uses [technical analysis indicators](http://www.investopedia.com/articles/ This investment advice is going to be either **long** or **short**. Long indicates that Gekko the asset should be bought and short indicates that it should be sold. -Below you can find simple and exemplary strategies that come with Gekko. These strategies come with Gekko and serve as examples, **for anything that involves real money we recommend you [write your own](./creating_a_strategy.md).** +If you are familiar with javascript you can easily create your own strategies. Here is a video explaining everything you need to know: + +[![youtube video on how to create gekko strategies](https://gekko.wizb.it/_static/create-strat-vid.jpg)](https://www.youtube.com/watch?v=6-74ZhrG0BE) + +Below you can find simple and exemplary strategies that come with Gekko. These strategies come with Gekko and serve as examples. Gekko currently comes with the following example strategies: From cdcd69407b78a47db2c0dbf49d0719bef3175d7f Mon Sep 17 00:00:00 2001 From: Mike van Rossum Date: Sat, 1 Sep 2018 13:16:07 +0800 Subject: [PATCH 7/8] [GB] catch another DNS error --- exchange/wrappers/binance.js | 3 ++- exchange/wrappers/gdax.js | 3 ++- exchange/wrappers/poloniex.js | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/exchange/wrappers/binance.js b/exchange/wrappers/binance.js index a995c67fb..9b3608008 100644 --- a/exchange/wrappers/binance.js +++ b/exchange/wrappers/binance.js @@ -82,7 +82,8 @@ const recoverableErrors = [ 'ETIMEDOUT', 'EHOSTUNREACH', // getaddrinfo EAI_AGAIN api.binance.com api.binance.com:443 - 'EAI_AGAIN' + 'EAI_AGAIN', + 'ENETUNREACH' ]; const includes = (str, list) => { diff --git a/exchange/wrappers/gdax.js b/exchange/wrappers/gdax.js index a5ad0f061..cfdc924ab 100644 --- a/exchange/wrappers/gdax.js +++ b/exchange/wrappers/gdax.js @@ -61,7 +61,8 @@ const recoverableErrors = [ 'HTTP 503 Error', 'socket hang up', 'EHOSTUNREACH', - 'EAI_AGAIN' + 'EAI_AGAIN', + 'ENETUNREACH' ]; const includes = (str, list) => { diff --git a/exchange/wrappers/poloniex.js b/exchange/wrappers/poloniex.js index d10b2e183..6583578ae 100644 --- a/exchange/wrappers/poloniex.js +++ b/exchange/wrappers/poloniex.js @@ -44,7 +44,8 @@ const recoverableErrors = [ 'Internal error. Please try again.', 'Connection timed out. Please try again.', // getaddrinfo EAI_AGAIN poloniex.com poloniex.com:443 - 'EAI_AGAIN' + 'EAI_AGAIN', + 'ENETUNREACH' ]; // errors that might mean From 87b702dd526c2792aae1b50e75d5d4a97112d0e2 Mon Sep 17 00:00:00 2001 From: Mike van Rossum Date: Mon, 3 Sep 2018 12:08:28 +0800 Subject: [PATCH 8/8] [GB] make sure we always check pending actions --- exchange/orders/sticky.js | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/exchange/orders/sticky.js b/exchange/orders/sticky.js index c41074c46..ff23fe2f7 100644 --- a/exchange/orders/sticky.js +++ b/exchange/orders/sticky.js @@ -207,21 +207,30 @@ class StickyOrder extends BaseOrder { this.status = states.OPEN; this.emitStatus(); + this.scheduleNextCheck(); + } + + scheduleNextCheck() { + // remove lock this.sticking = false; // check whether we had an action pending - if(this.cancelling) + if(this.cancelling) { return this.cancel(); + } - if(this.movingLimit) + if(this.movingLimit) { return this.moveLimit(); + } - if(this.movingAmount) + if(this.movingAmount) { return this.moveAmount(); + } // register check this.timeout = setTimeout(this.checkOrder, this.checkInterval); + } checkOrder() { @@ -245,8 +254,7 @@ class StickyOrder extends BaseOrder { // if we are already at limit we dont care where the top is // note: might be string VS float if(this.price == this.limit) { - this.timeout = setTimeout(this.checkOrder, this.checkInterval); - this.sticking = false; + this.scheduleNextCheck(); return; } @@ -264,8 +272,7 @@ class StickyOrder extends BaseOrder { return this.move(this.calculatePrice(ticker)); } - this.timeout = setTimeout(this.checkOrder, this.checkInterval); - this.sticking = false; + this.scheduleNextCheck(); }); return; @@ -409,7 +416,7 @@ class StickyOrder extends BaseOrder { this.sticking = true; this.move(this.limit); } else { - this.timeout = setTimeout(this.checkOrder, this.checkInterval); + this.scheduleNextCheck(); } return true; @@ -492,6 +499,7 @@ class StickyOrder extends BaseOrder { this.completing = true; clearTimeout(this.timeout); + this.api.cancelOrder(this.id, (err, filled, data) => { if(this.handleError(err)) { return;