diff --git a/config/strategies/BB.toml b/config/strategies/BB.toml new file mode 100644 index 000000000..a48e9c5f8 --- /dev/null +++ b/config/strategies/BB.toml @@ -0,0 +1,4 @@ +[bbands] +TimePeriod = 20 +NbDevUp = 2.25 +NbDevDn = 2 diff --git a/strategies/BB.js b/strategies/BB.js new file mode 100644 index 000000000..41ebb1c38 --- /dev/null +++ b/strategies/BB.js @@ -0,0 +1,94 @@ +/* + + BB strategy - okibcn 2018-01-03 + + */ +// helpers +var _ = require('lodash'); +var log = require('../core/log.js'); + +var BB = require('./indicators/BB.js'); + +// let's create our own method +var method = {}; + +// prepare everything our method needs +method.init = function() { + this.name = 'BB'; + this.nsamples = 0; + this.trend = { + zone: 'none', // none, top, high, low, bottom + duration: 0, + persisted: false + }; + + this.requiredHistory = this.tradingAdvisor.historySize; + + // define the indicators we need + this.addIndicator('bb', 'BB', this.settings.bbands); +} + + +// for debugging purposes log the last +// calculated parameters. +method.log = function(candle) { + var digits = 8; + var BB = this.indicators.bb; + //BB.lower; BB.upper; BB.middle are your line values + +log.debug('______________________________________'); + log.debug('calculated BB properties for candle ',this.nsamples); + + if (BB.upper>candle.close) log.debug('\t', 'Upper BB:', BB.upper.toFixed(digits)); + if (BB.middle>candle.close) log.debug('\t', 'Mid BB:', BB.middle.toFixed(digits)); + if (BB.lower>=candle.close) log.debug('\t', 'Lower BB:', BB.lower.toFixed(digits)); + log.debug('\t', 'price:', candle.close.toFixed(digits)); + if (BB.upper<=candle.close) log.debug('\t', 'Upper BB:', BB.upper.toFixed(digits)); + if (BB.middle<=candle.close) log.debug('\t', 'Mid BB:', BB.middle.toFixed(digits)); + if (BB.lower= BB.upper) zone = 'top'; + if ((price < BB.upper) && (price >= BB.middle)) zone = 'high'; + if ((price > BB.lower) && (price < BB.middle)) zone = 'low'; + if (price <= BB.lower) zone = 'bottom'; + log.debug('current zone: ',zone); + + + if (this.trend.zone == zone){ + // Ain't no zone change + log.debug('persisted'); + this.trend = { + zone: zone, // none, top, high, low, bottom + duration: this.trend.duration+1, + persisted: true + } + + this.advice(); + } + else { + // There is a zone change + log.debug('Leaving zone: ',this.trend.zone) + if (this.trend.zone == 'top') this.advice('short'); + if (this.trend.zone == 'bottom') this.advice('long'); + if (this.trend.zone == 'high') this.advice(); + if (this.trend.zone == 'low') this.advice(); + if (this.trend.zone == 'top') log.debug( '>>>>> SIGNALING ADVICE SHORT <<<<<<<<<<<<'); + if (this.trend.zone == 'bottom') log.debug('>>>>> SIGNALING ADVICE LONG <<<<<<<<<<<<'); + this.trend = { + zone: zone, // none, top, high, low, bottom + duration: 0, + persisted: false + } + } +} + +module.exports = method; diff --git a/strategies/indicators/BB.js b/strategies/indicators/BB.js new file mode 100644 index 000000000..1ad91966e --- /dev/null +++ b/strategies/indicators/BB.js @@ -0,0 +1,38 @@ +// no required indicators +// Bollinger Bands - Okibcn implementation 2018-01-02 + +var Indicator = function(BBSettings) { + this.input = 'price'; + this.settings = BBSettings; + // Settings: + // TimePeriod: The amount of samples used for the average. + // NbDevUp: The distance in stdev of the upper band from the SMA. + // NbDevDn: The distance in stdev of the lower band from the SMA. + this.prices = []; + this.diffs = []; + this.age = 0; + this.sum = 0; + this.sumsq = 0; + this.upper = 0; + this.middle = 0; + this.lower = 0; +} + +Indicator.prototype.update = function(price) { + var tail = this.prices[this.age] || 0; // oldest price in window + var diffsTail = this.diffs[this.age] || 0; // oldest average in window + + this.prices[this.age] = price; + this.sum += price - tail; + this.middle = this.sum / this.prices.length; // SMA value + + this.diffs[this.age] = (price - this.middle); + this.sumsq += this.diffs[this.age] ** 2 - diffsTail ** 2; + var stdev = Math.sqrt(this.sumsq) / this.prices.length; + + this.upper = this.middle + this.settings.NbDevUp * stdev; + this.lower = this.middle - this.settings.NbDevDn * stdev; + + this.age = (this.age + 1) % this.settings.TimePeriod +} +module.exports = Indicator;