-
Notifications
You must be signed in to change notification settings - Fork 400
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
24 changed files
with
3,065 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
/* | ||
BB strategy - okibcn 2018-01-03 | ||
*/ | ||
// helpers | ||
var _ = require('lodash'); | ||
var log = require('../core/log.js'); | ||
|
||
var BB = require('./indicators/BB.js'); | ||
var rsi = require('./indicators/RSI.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); | ||
this.addIndicator('rsi', 'RSI', this.settings); | ||
} | ||
|
||
|
||
// 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)); | ||
|
||
// var rsi = this.indicators.rsi; | ||
|
||
// log.debug('calculated RSI properties for candle:'); | ||
// log.debug('\t', 'rsi:', rsi.result.toFixed(digits)); | ||
// log.debug('\t', 'price:', candle.close.toFixed(digits)); | ||
} | ||
|
||
method.check = function (candle) { | ||
var BB = this.indicators.bb; | ||
var price = candle.close; | ||
this.nsamples++; | ||
|
||
var rsi = this.indicators.rsi; | ||
var rsiVal = rsi.result; | ||
|
||
// 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); | ||
log.debug('current trend duration: ', this.trend.duration); | ||
|
||
if (this.trend.zone == zone) { | ||
this.trend = { | ||
zone: zone, // none, top, high, low, bottom | ||
duration: this.trend.duration+1, | ||
persisted: true | ||
} | ||
} | ||
else { | ||
this.trend = { | ||
zone: zone, // none, top, high, low, bottom | ||
duration: 0, | ||
persisted: false | ||
} | ||
} | ||
|
||
if (price <= BB.lower && rsiVal <= this.settings.thresholds.low && this.trend.duration >= this.settings.thresholds.persistence) { | ||
this.advice('long') | ||
} | ||
if (price >= BB.middle && rsiVal >= this.settings.thresholds.high) { | ||
this.advice('short') | ||
} | ||
|
||
// this.trend = { | ||
// zone: zone, // none, top, high, low, bottom | ||
// duration: 0, | ||
// persisted: false | ||
|
||
|
||
} | ||
|
||
module.exports = method; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
interval = 14 | ||
|
||
[thresholds] | ||
low = 40 | ||
high = 40 | ||
persistence = 9 | ||
|
||
[bbands] | ||
TimePeriod = 20 | ||
NbDevUp = 2 | ||
NbDevDn = 2 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Source: https://raw.githubusercontent.com/atselevich/gekko/develop/strategies/BBRSI.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
/* | ||
MACD - DJM 31/12/2013 | ||
(updated a couple of times since, check git history) | ||
*/ | ||
|
||
// helpers | ||
var _ = require('lodash'); | ||
var log = require('../core/log.js'); | ||
|
||
// let's create our own method | ||
var method = {}; | ||
|
||
// prepare everything our method needs | ||
method.init = function() { | ||
// keep state about the current trend | ||
// here, on every new candle we use this | ||
// state object to check if we need to | ||
// report it. | ||
this.trend = { | ||
direction: 'none', | ||
duration: 0, | ||
persisted: false, | ||
adviced: false | ||
}; | ||
|
||
this.boughtAt = 0; | ||
// how many candles do we need as a base | ||
// before we can start giving advice? | ||
this.requiredHistory = this.tradingAdvisor.historySize; | ||
|
||
// define the indicators we need | ||
this.addIndicator('dave', 'Dave', this.settings); | ||
this.boughtPriceCount = 0; | ||
this.maxExposureCount = 0; | ||
} | ||
|
||
// what happens on every new candle? | ||
method.update = function(candle) { | ||
// nothing! | ||
} | ||
|
||
method.check = function() { | ||
|
||
//If long short average / long average < 1.00 then we have a dip | ||
var shortAverage = this.indicators.dave.short.result; | ||
var longAverage = this.indicators.dave.long.result; | ||
var lastPrice = this.indicators.dave.lastPrice; | ||
var change = shortAverage/longAverage; | ||
var priceCountDiff = this.indicators.dave.priceCount - this.boughtPriceCount; | ||
|
||
var maxExposureHitCountDiff = this.indicators.dave.priceCount - this.maxExposureCount; | ||
var weHitMaxExposure = this.maxExposureCount > 0; | ||
|
||
if( this.boughtAt > 0 ){ | ||
var change = lastPrice / this.boughtAt; | ||
// | ||
// if last price / buy price > 1.00 then we have a lift | ||
// lift size is last_price / buy_price - 1.00 | ||
// if lift_size > threshold to sell | ||
// then sell and mark that we are out | ||
var dipSize = 1.0 - change; | ||
var liftSize = change - 1.0; | ||
|
||
if( change > 1.0 ){ | ||
log.debug("*******","We have lift",shortAverage.toFixed(4),longAverage.toFixed(4),liftSize.toFixed(8)); | ||
|
||
if(liftSize > this.settings.thresholds.up){ | ||
this.advice('short'); | ||
log.debug("******",'We sold',lastPrice); | ||
this.boughtAt = 0; | ||
this.maxExposureCount = 0; | ||
} | ||
} else if( dipSize > 0 ){ | ||
if( dipSize > this.settings.thresholds.getOut ){ | ||
log.debug("*******","Get Out!",shortAverage.toFixed(4),longAverage.toFixed(4),dipSize.toFixed(8)); | ||
this.advice('short'); | ||
this.boughtAt = 0; | ||
//this.maxExposureCount = this.indicators.dave.priceCount; | ||
} | ||
} | ||
|
||
if( this.boughtAt > 0 && priceCountDiff > this.settings.thresholds.maxExposureLength){ | ||
this.advice('short'); | ||
this.boughtAt = 0; | ||
//this.maxExposureCount = this.indicators.dave.priceCount; | ||
} | ||
} else if( change < 1.0 ){ | ||
// dip size is 1 - above | ||
var dipSize = 1.0 - change; | ||
log.debug("*******","We have a dip",shortAverage.toFixed(4),longAverage.toFixed(4),dipSize.toFixed(8)); | ||
|
||
// if dip size is greater than threshold to buy | ||
if( weHitMaxExposure && maxExposureHitCountDiff < this.settings.thresholds.maxExposureLength){ | ||
log.debug("******","Skipping any buy because we just hit a max exposure"); | ||
this.advice(); | ||
return; | ||
} | ||
|
||
if( dipSize > this.settings.thresholds.down ){ | ||
// then buy and save the price to buy price and mark that we bought | ||
this.advice('long'); | ||
this.boughtAt = lastPrice; | ||
this.boughtPriceCount = this.indicators.dave.priceCount; | ||
log.debug('\n','*****************',"We bought", lastPrice, this.boughtPriceCount,'\n'); | ||
this.maxExposureCount = 0; | ||
} | ||
} else { | ||
|
||
//log.debug('In no trend'); | ||
|
||
// we're not in an up nor in a downtrend | ||
// but for now we ignore sideways trends | ||
// | ||
// read more @link: | ||
// | ||
// https://github.com/askmike/gekko/issues/171 | ||
|
||
// this.trend = { | ||
// direction: 'none', | ||
// duration: 0, | ||
// persisted: false, | ||
// adviced: false | ||
// }; | ||
|
||
this.advice(); | ||
} | ||
} | ||
|
||
module.exports = method; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
short = 2 | ||
long = 10 | ||
|
||
[thresholds] | ||
down = 0.01 | ||
up = 0.01 | ||
getOut = 0.03 | ||
persistence = 1 | ||
maxExposureLength = 30 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Source: https://raw.githubusercontent.com/digidigo/gekko/stable/strategies/Dave.js |
Oops, something went wrong.