Skip to content

Commit

Permalink
minor overhaul to trend_ema strat - added whipsaw filtering via std. …
Browse files Browse the repository at this point in the history
…deviation (--neutral_rate=auto), trim preroll of sim result graph
  • Loading branch information
Carlos Rodriguez committed May 21, 2017
1 parent 0cf5855 commit 35dde49
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 12 deletions.
2 changes: 1 addition & 1 deletion commands/sim.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ module.exports = function container (get, set, clear) {
console.log('buy hold', buy_hold.format('0.00000000').yellow + ' (' + n(buy_hold_profit).format('0.00%') + ')')
console.log('vs. buy hold', n(s.balance.currency).subtract(buy_hold).divide(buy_hold).format('0.00%').yellow)
console.log(s.my_trades.length + ' trades over ' + s.day_count + ' days (avg ' + n(s.my_trades.length / s.day_count).format('0.00') + ' trades/day)')
var data = s.lookback.map(function (period) {
var data = s.lookback.slice(0, s.lookback.length - so.min_periods).map(function (period) {
return {
time: period.time,
open: period.open,
Expand Down
38 changes: 28 additions & 10 deletions extensions/trend_ema/strategy.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ module.exports = function container (get, set, clear) {
this.option('period', 'period length', String, '1h')
this.option('min_periods', 'min. number of history periods', Number, 36)
this.option('trend_ema', 'number of periods for trend EMA', Number, 34)
this.option('buy_rate', 'buy if trend ema rate between 0 and this positive float', Number, 0)
this.option('sell_rate', 'sell if trend ema rate between 0 and this negative float', Number, 0)
this.option('max_buy_duration', 'avoid buy if trend duration over this number', Number, 1)
this.option('max_sell_duration', 'avoid sell if trend duration over this number', Number, 1)
this.option('buy_rate', 'buy if trend EMA rate between neutral_rate and this positive float', Number, 0)
this.option('sell_rate', 'sell if trend EMA rate between neutral_rate * -1 and this negative float', Number, 0)
this.option('neutral_rate', 'avoid signals when trend EMA rate is under this absolute value', Number, 'auto')
this.option('max_buy_duration', 'avoid buy if trend duration over this number', Number, 0)
this.option('max_sell_duration', 'avoid sell if trend duration over this number', Number, 0)
this.option('oversold_rsi_periods', 'number of periods for oversold RSI', Number, 14)
this.option('oversold_rsi', 'buy when RSI reaches this value', Number, 0)
},
Expand All @@ -29,8 +30,15 @@ module.exports = function container (get, set, clear) {
},

onPeriod: function (s, cb) {
if (s.options.neutral_rate === 'auto' || s.options.neutral_rate_auto) {
s.options.neutral_rate_auto = true
get('lib.stddev')(s, 'trend_ema_stddev', Math.floor(s.options.trend_ema / 2), 'trend_ema_rate')
if (typeof s.period.trend_ema_stddev === 'number') {
s.options.neutral_rate = s.period.trend_ema_stddev
}
}
if (typeof s.period.oversold_rsi === 'number') {
if (s.period.oversold_rsi <= s.options.oversold_rsi) {
if (s.period.oversold_rsi <= s.options.oversold_rsi && !s.oversold) {
s.oversold = true
console.log(('\noversold at ' + s.period.oversold_rsi + ' RSI, preparing to buy\n').cyan)
}
Expand All @@ -43,24 +51,24 @@ module.exports = function container (get, set, clear) {
}
}
if (typeof s.period.trend_ema_rate === 'number') {
if (s.period.trend_ema_rate >= 0) {
if (s.period.trend_ema_rate > s.options.neutral_rate) {
if (s.trend !== 'up') {
s.acted_on_trend = false
s.trend_duration = 0
}
s.trend_duration++
s.trend = 'up'
s.signal = (!s.options.buy_rate || s.period.trend_ema_rate <= s.options.buy_rate) && (!s.options.max_buy_duration || s.trend_duration <= s.options.max_buy_duration) && !s.acted_on_trend ? 'buy' : null
s.signal = (!s.options.buy_rate || s.period.trend_ema_rate <= s.options.buy_rate) && (!s.options.max_buy_duration || !s.trend || s.trend_duration <= s.options.max_buy_duration) && !s.acted_on_trend ? 'buy' : null
s.cancel_down = false
}
else if (!s.cancel_down) {
else if (!s.cancel_down && s.period.trend_ema_rate < (s.options.neutral_rate * -1)) {
if (s.trend !== 'down') {
s.acted_on_trend = false
s.trend_duration = 0
}
s.trend_duration++
s.trend = 'down'
s.signal = (!s.options.sell_rate || s.period.trend_ema_rate >= s.options.sell_rate) && (!s.options.max_sell_duration || s.trend_duration <= s.options.max_sell_duration) && !s.acted_on_trend ? 'sell' : null
s.signal = (!s.options.sell_rate || s.period.trend_ema_rate >= s.options.sell_rate) && (!s.options.max_sell_duration || !s.trend || s.trend_duration <= s.options.max_sell_duration) && !s.acted_on_trend ? 'sell' : null
}
}
cb()
Expand All @@ -69,11 +77,21 @@ module.exports = function container (get, set, clear) {
onReport: function (s) {
var cols = []
if (typeof s.period.trend_ema_rate === 'number') {
cols.push(z(8, n(s.period.trend_ema_rate).format('0.0000'), ' ')[s.period.trend_ema_rate >= 0 ? 'green' : 'red'])
var color = 'grey'
if (s.period.trend_ema_rate > s.options.neutral_rate) {
color = 'green'
}
else if (s.period.trend_ema_rate < (s.options.neutral_rate * -1)) {
color = 'red'
}
cols.push(z(8, n(s.period.trend_ema_rate).format('0.0000'), ' ')[color])
}
else {
cols.push(' ')
}
if (typeof s.period.trend_ema_stddev === 'number') {
cols.push(z(8, n(s.period.trend_ema_stddev).format('0.0000'), ' ').grey)
}
return cols
}
}
Expand Down
3 changes: 2 additions & 1 deletion lib/_codemap.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ module.exports = {
'ema': require('./ema'),
'engine': require('./engine'),
'normalize-selector': require('./normalize-selector'),
'rsi': require('./rsi')
'rsi': require('./rsi'),
'stddev': require('./stddev')
}
24 changes: 24 additions & 0 deletions lib/stddev.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module.exports = function container (get, set, clear) {
return function stddev (s, key, length, source_key) {
if (typeof s.period[source_key] === 'number') {
var sum = s.period[source_key]
var sum_len = 1
for (var idx = 0; idx < length; idx++) {
if (typeof s.lookback[idx][source_key] === 'number') {
sum += s.lookback[idx][source_key]
sum_len++
}
else {
break;
}
}
var avg = sum / sum_len
var var_sum = 0
for (var idx = 0; idx < sum_len - 1; idx++) {
var_sum += Math.pow(s.lookback[idx][source_key] - avg, 2)
}
var variance = var_sum / sum_len
s.period[key] = Math.sqrt(variance)
}
}
}

0 comments on commit 35dde49

Please sign in to comment.