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

Commit

Permalink
Feature/strategy keltner channel (#1516)
Browse files Browse the repository at this point in the history
* add docker mount for forex_analytics models (#1369)

* Implementation of Keltner Channels Strategy
  • Loading branch information
IvoPereira authored and DeviaVir committed Mar 19, 2018
1 parent a2db1e8 commit 39d4bbd
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 1 deletion.
81 changes: 81 additions & 0 deletions extensions/strategies/kc/strategy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
var z = require('zero-fill')
, n = require('numbro')
, kc = require('../../../lib/kc')
, Phenotypes = require('../../../lib/phenotype')

module.exports = {
name: 'kc',
description: 'Buy when (Signal ≤ Lower Keltner Channel) and sell when (Signal ≥ Upper Keltner Channel).',

getOptions: function () {
this.option('period', 'period length, same as --period_length', String, '1h')
this.option('period_length', 'period length, same as --period', String, '1h')
this.option('kc_size', 'period size', Number, 20)
this.option('kc_multiplier', 'multiplier for the average true range', Number, 1)
this.option('kc_upper_channel_pct', 'pct the current price should be near the keltner upper channel before we sell', Number, 0)
this.option('kc_lower_channel_pct', 'pct the current price should be near the keltner lower channel before we buy', Number, 0)
},

calculate: function (s) {
// calculate Keltner Channels
kc(s, 'kc', s.options.kc_size)
},

onPeriod: function (s, cb) {
if (s.period.kc) {
if (s.period.kc.upper && s.period.kc.lower) {
let upperChannel = s.period.kc.upper[s.period.kc.upper.length-1]
let lowerChannel = s.period.kc.lower[s.period.kc.lower.length-1]
if (s.period.close > (upperChannel / 100) * (100 - s.options.kc_upper_channel_pct)) {
s.signal = 'sell'
} else if (s.period.close < (lowerChannel / 100) * (100 + s.options.kc_lower_channel_pct)) {
s.signal = 'buy'
} else {
s.signal = null // hold
}
}
}
cb()
},

onReport: function (s) {
var cols = []
if (s.period.kc) {
if (s.period.kc.upper && s.period.kc.lower) {
let upperChannel = s.period.kc.upper[s.period.kc.upper.length-1]
let lowerChannel = s.period.kc.lower[s.period.kc.lower.length-1]
var color = 'grey'
if (s.period.close > (upperChannel / 100) * (100 - s.options.kc_upper_channel_pct)) {
color = 'green'
} else if (s.period.close < (lowerChannel / 100) * (100 + s.options.kc_lower_channel_pct)) {
color = 'red'
}
cols.push(z(8, n(s.period.close).format('+00.0000'), ' ')[color])
cols.push(z(8, n(lowerChannel).format('0.000000').substring(0,7), ' ').cyan)
cols.push(z(8, n(upperChannel).format('0.000000').substring(0,7), ' ').cyan)
}
}
else {
cols.push(' ')
}
return cols
},

phenotypes: {
// -- common
period_length: Phenotypes.RangePeriod(1, 120, 'm'),
markdown_buy_pct: Phenotypes.RangeFloat(-1, 5),
markup_sell_pct: Phenotypes.RangeFloat(-1, 5),
order_type: Phenotypes.ListOption(['maker', 'taker']),
sell_stop_pct: Phenotypes.Range0(1, 50),
buy_stop_pct: Phenotypes.Range0(1, 50),
profit_stop_enable_pct: Phenotypes.Range0(1, 20),
profit_stop_pct: Phenotypes.Range(1,20),

// -- strategy
kc_size: Phenotypes.Range(1, 40),
kc_upper_channel_pct: Phenotypes.RangeFloat(-1, 30),
kc_lower_channel_pct: Phenotypes.RangeFloat(-1, 30)
}
}

2 changes: 1 addition & 1 deletion lib/bollinger.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Linear Regression Curve
// Bollinger Bands
var bollingerbands = require('bollinger-bands')
module.exports = function bollinger (s, key, length, source_key) {
if (!source_key) source_key = 'close'
Expand Down
18 changes: 18 additions & 0 deletions lib/kc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Keltner Channels
var keltnerchannel = require('keltnerchannel').kc
module.exports = function kc (s, key, length, source_key) {
if (!source_key) source_key = 'close'
if (s.lookback.length > length) {
let data = []
for (var i=length-1; i>=0; i--) {
data.push({
high: s.lookback[i].high,
low: s.lookback[i].low,
close: s.lookback[i].close
})
}
let result = keltnerchannel(data, s.options.kc_size, s.options.kc_multiplier)
s.period[key] = result
}
}

5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"ip": "~1.1.5",
"jasmine": "^2.8.0",
"jquery": "^3.2.1",
"keltnerchannel": "^1.4.2",
"kraken-api": "^1.0.0",
"lint-staged": "^7.0.0",
"lodash": "^4.17.4",
Expand Down

0 comments on commit 39d4bbd

Please sign in to comment.