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

Create BB strategy #1623

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions config/strategies/BB.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[bbands]
TimePeriod = 20
NbDevUp = 2.25
NbDevDn = 2
94 changes: 94 additions & 0 deletions strategies/BB.js
Original file line number Diff line number Diff line change
@@ -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<candle.close) log.debug('\t', 'Lower BB:', BB.lower.toFixed(digits));
log.debug('\t', 'Band gap: ', BB.upper.toFixed(digits) - BB.lower.toFixed(digits));
}

method.check = function(candle) {
var BB = this.indicators.bb;
var price = candle.close;
this.nsamples++;

// price Zone detection
var zone = 'none';
if (price >= 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');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than two different if statements where the zone equals the same, why not?

if (this.trend.zone === 'top') {
  log.debug('>>>>>   SIGNALING ADVICE SHORT   <<<<<<<<<<<<');
  this.advice('short');
}

Perhaps a switch statement would be more readable?

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;
38 changes: 38 additions & 0 deletions strategies/indicators/BB.js
Original file line number Diff line number Diff line change
@@ -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;