This repository has been archived by the owner on Feb 15, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add strategies that utilize TA-Lib and Tulip-Lib (#1621)
* Add Backing Libs ta-lib Bollinger Bands ta-lib Stochastic Oscillator ta-lib Stochastic RSI Oscillator Tulip-lib Bollinger Bands Tulip-lib MACD Tulip-lib RSI Tulip-lib Stochastic Oscillator Tulip-lib Stochastic RSI Oscillator * Add strategy ta_srsi_bollinger This Strategy uses SRSI to detect when to buy and sell verifying price position using Bollinger Bands * Add Strategy ti_stoch_bollinger This strategy uses Stochastic Oscillator to detect buy and sell signals verifying using bollinger bands This utilizes the Tulip Libs * Add strategy ti_bollinger This is a duplicate of native bollinger strategy but implemented using Tulip libs. This was for testing the ti_bollinger backing lib. This can be used by itself but does not detect trends so most likely will result in losses. * Add Strategy ti_stoch This is the Stochastic Oscillator implmented using the Tulip lib. this buys and sells at set SO crossover points. This is mainly for testing the backing library. It can be used standalone but does not check for trends so it is likely to result in losses * Add Stragegy ti_stoch_bollinger This strategy buys and sells using Stochastic Oscillator crossover points and verifies using bollinger. implemented us Tulip lib * Fix bugs in Stoch RSI. add option for passing in market data * Fix bugs in Stoch. add option for passing in market data * Set Bollinger time divider to default. adjust but/sell calculation
- Loading branch information
1 parent
2a358a4
commit f7f29b9
Showing
13 changed files
with
1,225 additions
and
0 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,161 @@ | ||
let z = require('zero-fill') | ||
, n = require('numbro') | ||
, ta_srsi = require('../../../lib/ta_stochrsi') | ||
, ta_bollinger = require('../../../lib/ta_bollinger') | ||
, Phenotypes = require('../../../lib/phenotype') | ||
module.exports = { | ||
name: 'srsi_bollinger', | ||
description: 'Stochastic RSI BollingerBand Strategy', | ||
|
||
getOptions: function () { | ||
this.option('period', 'period length, same as --period_length', String, '5m') | ||
this.option('period_length', 'period length, same as --period', String, '5m') | ||
this.option('min_periods', 'min. number of history periods', Number, 200) | ||
this.option('rsi_periods', 'number of RSI periods', 14) | ||
this.option('srsi_periods', 'number of Stochastic RSI periods',Number, 9) | ||
this.option('srsi_k', '%D line', Number, 3) | ||
this.option('srsi_d', '%D line', Number, 3) | ||
this.option('srsi_k_sell', 'K must be above this before selling', Number, 60) | ||
this.option('srsi_k_buy', 'K must be below this before buying', Number, 30) | ||
this.option('srsi_dType','D type mode : SMA,EMA,WMA,DEMA,TEMA,TRIMA,KAMA,MAMA,T3', String, 'SMA'), | ||
|
||
//'SMA','EMA','WMA','DEMA','TEMA','TRIMA','KAMA','MAMA','T3' | ||
|
||
|
||
this.option('bollinger_size', 'period size', Number, 14) | ||
this.option('bollinger_updev', 'Upper Bollinger Time Divisor', Number, 2) | ||
this.option('bollinger_dndev', 'Lower Bollinger Time Divisor', Number, 2) | ||
this.option('bollinger_dType','mode: : SMA,EMA,WMA,DEMA,TEMA,TRIMA,KAMA,MAMA,T3', String, 'SMA') | ||
this.option('bollinger_upper_bound_pct', 'pct the current price should be near the bollinger upper bound before we sell', Number, 1) | ||
this.option('bollinger_lower_bound_pct', 'pct the current price should be near the bollinger lower bound before we buy', Number, 1) | ||
|
||
|
||
}, | ||
|
||
|
||
calculate: function (s) { | ||
|
||
if (s.in_preroll) return | ||
|
||
}, | ||
|
||
onPeriod: function (s, cb) { | ||
//make sure we have all values | ||
if (s.in_preroll) return cb() | ||
|
||
ta_bollinger(s,'tabollinger',s.options.bollinger_size, s.options.bollinger_updev, s.options.bollinger_dndev, s.options.bollinger_dType). | ||
then(function(inbol){ | ||
ta_srsi(s, 'srsi', s.options.srsi_periods, s.options.srsi_k, s.options.srsi_d, s.options.srsi_dType). | ||
then(function(inres) { | ||
|
||
if (!inres) return cb() | ||
var divergent = inres.outFastK[inres.outFastK.length-1] - inres.outFastD[inres.outFastD.length-1] | ||
s.period.srsi_D = inres.outFastD[inres.outFastD.length-1] | ||
s.period.srsi_K = inres.outFastK[inres.outFastK.length-1] | ||
var last_divergent = inres.outFastK[inres.outFastK.length-2] - inres.outFastD[inres.outFastD.length-2] | ||
var _switch = 0//s.lookback[0]._switch | ||
var nextdivergent = (( divergent + last_divergent ) /2) + (divergent - last_divergent) | ||
if ((last_divergent <= 0 && (divergent > 0)) ) _switch = 1 // price rising | ||
if ((last_divergent >= 0 && (divergent < 0)) ) _switch = -1 // price falling | ||
|
||
s.period.divergent = divergent | ||
s.period._switch = _switch | ||
|
||
|
||
|
||
let upperBound = inbol.outRealUpperBand[inbol.outRealUpperBand.length-1] | ||
let lowerBound = inbol.outRealLowerBand[inbol.outRealLowerBand.length-1] | ||
let midBound =inbol.outRealMiddleBand[inbol.outRealMiddleBand.length-1] | ||
if (!s.period.bollinger) s.period.bollinger = {} | ||
|
||
s.period.bollinger.upperBound = upperBound | ||
s.period.bollinger.lowerBound = lowerBound | ||
s.period.bollinger.midBound = midBound | ||
|
||
|
||
// K is fast moving | ||
|
||
s.signal = null | ||
if (_switch != 0 ) | ||
{ | ||
if (s.period.close > ((upperBound / 100) * (100 - s.options.bollinger_upper_bound_pct)) && nextdivergent < divergent && _switch == -1 && s.period.srsi_K > s.options.srsi_k_sell) | ||
{ | ||
s.signal = 'sell' | ||
} | ||
else | ||
if (s.period.close < ((lowerBound / 100) * (100 + s.options.bollinger_lower_bound_pct)) && nextdivergent >= divergent && _switch == 1 && s.period.srsi_K < s.options.srsi_k_buy) | ||
{ | ||
s.signal = 'buy' | ||
} | ||
|
||
} | ||
|
||
cb() | ||
}).catch(function(){ | ||
cb()}) | ||
|
||
}).catch(function(){ | ||
cb()}) | ||
|
||
}, | ||
|
||
onReport: function (s) { | ||
var cols = [] | ||
if (s.period.bollinger) { | ||
if (s.period.bollinger.upperBound && s.period.bollinger.lowerBound) { | ||
let upperBound = s.period.bollinger.upperBound | ||
let lowerBound = s.period.bollinger.lowerBound | ||
var color = 'grey' | ||
if (s.period.close > (upperBound / 100) * (100 - s.options.bollinger_upper_bound_pct)) { | ||
color = 'green' | ||
} else if (s.period.close < (lowerBound / 100) * (100 + s.options.bollinger_lower_bound_pct)) { | ||
color = 'red' | ||
} | ||
cols.push(z(8, n(s.period.close).format('+00.0000'), ' ')[color]) | ||
cols.push(z(8, n(lowerBound).format('0.000000').substring(0,7), ' ').cyan) | ||
cols.push(z(8, n(upperBound).format('0.000000').substring(0,7), ' ').cyan) | ||
cols.push(z(8, n(s.period.srsi_D).format('0.0000').substring(0,7), ' ').cyan) | ||
cols.push(z(8, n(s.period.srsi_K).format('0.0000').substring(0,7), ' ').cyan) | ||
cols.push(z(5, n(s.period.divergent).format('0').substring(0,7), ' ').cyan) | ||
cols.push(z(2, n(s.period._switch).format('0').substring(0,2), ' ').cyan) | ||
} | ||
} | ||
else { | ||
cols.push(' ') | ||
} | ||
return cols | ||
}, | ||
|
||
phenotypes: | ||
{ | ||
// -- common | ||
period_length: Phenotypes.ListOption(['1m', '2m', '3m', '4m', '5m', '10m','15m']),//, '10m','15m','30m','45m','60m' | ||
min_periods: Phenotypes.Range(52, 150), | ||
markdown_buy_pct: Phenotypes.RangeFactor(-1.0, 1.0, 0.1), | ||
markup_sell_pct: Phenotypes.RangeFactor(-1.0, 1.0, 0.1), | ||
order_type: Phenotypes.ListOption(['maker', 'taker']), | ||
sell_stop_pct: Phenotypes.RangeFactor(0.0, 50.0,0.1), | ||
buy_stop_pct: Phenotypes.RangeFactor(0.0, 50.0,0.1), | ||
profit_stop_enable_pct: Phenotypes.RangeFactor(0.0, 5.0, 0.1), | ||
profit_stop_pct: Phenotypes.RangeFactor(0.0, 50.0, 0.1), | ||
|
||
// -- strategy | ||
rsi_periods: Phenotypes.Range(10, 20), | ||
srsi_periods: Phenotypes.Range(5, 30), | ||
srsi_k: Phenotypes.Range(1, 30), | ||
srsi_d: Phenotypes.Range(1, 30), | ||
srsi_k_sell: Phenotypes.RangeFactor(0.0, 100.0, 1.0), | ||
srsi_k_buy: Phenotypes.RangeFactor(0.0, 100.0, 1.0), | ||
srsi_dType: Phenotypes.ListOption(['SMA','EMA','WMA','DEMA','TEMA','TRIMA','KAMA','MAMA','T3']), | ||
|
||
|
||
|
||
bollinger_size: Phenotypes.RangeFactor(10, 25, 1), | ||
bollinger_updev: Phenotypes.RangeFactor(1, 3.0, 0.1), | ||
bollinger_dndev: Phenotypes.RangeFactor(1, 3.0, 0.1), | ||
bollinger_dType: Phenotypes.ListOption(['SMA','EMA','WMA','DEMA','TEMA','TRIMA','KAMA','MAMA','T3']), | ||
bollinger_upper_bound_pct: Phenotypes.RangeFactor(0.0, 100.0, 1.0), | ||
bollinger_lower_bound_pct: Phenotypes.RangeFactor(0.0, 100.0, 1.0) | ||
|
||
} | ||
} |
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,150 @@ | ||
let z = require('zero-fill') | ||
, n = require('numbro') | ||
, ta_stoch = require('../../../lib/ta_stoch') | ||
, ta_bollinger = require('../../../lib/ta_bollinger') | ||
, Phenotypes = require('../../../lib/phenotype') | ||
module.exports = { | ||
name: 'ta_stoch_bollinger', | ||
description: 'Stochastic BollingerBand Strategy', | ||
|
||
getOptions: function () { | ||
this.option('period', 'period length, same as --period_length', String, '5m') | ||
this.option('period_length', 'period length, same as --period', String, '5m') | ||
this.option('min_periods', 'min. number of history periods', Number, 200) | ||
this.option('rsi_periods', 'Time period for building the Fast-K line', Number, 14) | ||
this.option('stoch_periods', 'Time period for building the Fast-K line', Number, 5) | ||
this.option('stoch_k', 'Smoothing for making the Slow-K line. Usually set to 3', Number, 3) | ||
this.option('stoch_k_ma_type','Type of Moving Average for Slow-K : SMA,EMA,WMA,DEMA,TEMA,TRIMA,KAMA,MAMA,T3', String, 'SMA'), | ||
this.option('stoch_d', 'Smoothing for making the Slow-D line', Number, 3) | ||
this.option('stoch_d_ma_type','Type of Moving Average for Slow-D : SMA,EMA,WMA,DEMA,TEMA,TRIMA,KAMA,MAMA,T3', String, 'SMA'), | ||
this.option('stoch_k_sell', 'K must be above this before selling', Number, 70) | ||
this.option('stoch_k_buy', 'K must be below this before buying', Number, 30) | ||
|
||
this.option('bollinger_size', 'period size', Number, 14) | ||
this.option('bollinger_updev', '', Number, 2) | ||
this.option('bollinger_dndev', '', Number, 2) | ||
this.option('bollinger_dType','mode: : SMA,EMA,WMA,DEMA,TEMA,TRIMA,KAMA,MAMA,T3', String, 'SMA') | ||
this.option('bollinger_upper_bound_pct', 'pct the current price should be near the bollinger upper bound before we sell', Number,0) | ||
this.option('bollinger_lower_bound_pct', 'pct the current price should be near the bollinger lower bound before we buy', Number, 0) | ||
}, | ||
|
||
|
||
calculate: function (s) { | ||
if (s.in_preroll) return | ||
}, | ||
|
||
onPeriod: function (s, cb) { | ||
//make sure we have all values | ||
if (s.in_preroll) return cb() | ||
ta_bollinger(s,'tabollinger',s.options.bollinger_size, s.options.bollinger_updev, s.options.bollinger_dndev, s.options.bollinger_dType). | ||
then(function(inbol){ | ||
ta_stoch(s, 'stoch', s.options.stoch_periods, s.options.stoch_k, s.options.stoch_k_ma_type, s.options.stoch_d, s.options.stoch_d_ma_type). | ||
then(function(inres) { | ||
|
||
if (!inres) return cb() | ||
var divergent = inres.k[inres.k.length-1] - inres.d[inres.k.length-1] | ||
s.period.stoch_D = inres.d[inres.d.length-1] | ||
s.period.stoch_K = inres.k[inres.k.length-1] | ||
var last_divergent = inres.k[inres.k.length-2] - inres.d[inres.d.length-2] | ||
var _switch = 0 | ||
var nextdivergent = (( divergent + last_divergent ) /2) + (divergent - last_divergent) | ||
if ((last_divergent <= 0 && (divergent > 0)) ) _switch = 1 // price rising | ||
if ((last_divergent >= 0 && (divergent < 0)) ) _switch = -1 // price falling | ||
|
||
s.period.divergent = divergent | ||
s.period._switch = _switch | ||
|
||
let upperBound = inbol.outRealUpperBand[inbol.outRealUpperBand.length-1] | ||
let lowerBound = inbol.outRealLowerBand[inbol.outRealLowerBand.length-1] | ||
let midBound =inbol.outRealMiddleBand[inbol.outRealMiddleBand.length-1] | ||
if (!s.period.bollinger) s.period.bollinger = {} | ||
|
||
s.period.bollinger.upperBound = upperBound | ||
s.period.bollinger.lowerBound = lowerBound | ||
s.period.bollinger.midBound = midBound | ||
|
||
|
||
// K is fast moving | ||
|
||
s.signal = null | ||
if (_switch != 0 ) | ||
{ | ||
if (s.period.close >= midBound && s.period.close >= ((upperBound / 100) * (100 + s.options.bollinger_upper_bound_pct)) && nextdivergent < divergent && _switch == -1 && s.period.stoch_K > s.options.stoch_k_sell) | ||
{ | ||
s.signal = 'sell' | ||
} | ||
else | ||
if (s.period.close < (lowerBound / 100) * (100 + s.options.bollinger_lower_bound_pct) && nextdivergent >= divergent && _switch == 1 && s.period.stoch_K < s.options.stoch_k_buy) | ||
{ | ||
s.signal = 'buy' | ||
} | ||
} | ||
|
||
cb() | ||
}).catch(function(){ | ||
cb()}) | ||
|
||
}).catch(function(){ | ||
cb()}) | ||
}, | ||
|
||
onReport: function (s) { | ||
var cols = [] | ||
if (s.period.bollinger) { | ||
if (s.period.bollinger.upperBound && s.period.bollinger.lowerBound) { | ||
let upperBound = s.period.bollinger.upperBound | ||
let lowerBound = s.period.bollinger.lowerBound | ||
var color = 'grey' | ||
if (s.period.close > (upperBound / 100) * ( 100 + s.options.bollinger_upper_bound_pct)) { color = 'green' | ||
} | ||
if (s.period.close < (lowerBound / 100) * ( 100 - s.options.bollinger_lower_bound_pct)) { color = 'red' | ||
} | ||
cols.push(z(8, n(s.period.close).format('+00.0000'), ' ')[color]) | ||
cols.push(z(8, n(lowerBound).format('0.000000').substring(0,7), ' ').cyan) | ||
cols.push(z(8, n(upperBound).format('0.000000').substring(0,7), ' ').cyan) | ||
cols.push(z(8, n(s.period.stoch_D).format('0.0000').substring(0,7), ' ').cyan) | ||
cols.push(z(8, n(s.period.stoch_K).format('0.0000').substring(0,7), ' ').cyan) | ||
cols.push(z(5, n(s.period.divergent).format('0').substring(0,7), ' ').cyan) | ||
cols.push(z(2, n(s.period._switch).format('0').substring(0,2), ' ').cyan) | ||
} | ||
} | ||
else { | ||
cols.push(' ') | ||
} | ||
return cols | ||
}, | ||
|
||
phenotypes: | ||
{ | ||
// -- common | ||
period_length: Phenotypes.ListOption(['1m', '2m', '3m', '4m', '5m', '10m','15m']),//, '10m','15m','30m','45m','60m' | ||
min_periods: Phenotypes.Range(52, 150), | ||
markdown_buy_pct: Phenotypes.RangeFactor(-1.0, 1.0, 0.1), | ||
markup_sell_pct: Phenotypes.RangeFactor(-1.0, 1.0, 0.1), | ||
order_type: Phenotypes.ListOption(['maker', 'taker']), | ||
sell_stop_pct: Phenotypes.RangeFactor(0.0, 50.0,0.1), | ||
buy_stop_pct: Phenotypes.RangeFactor(0.0, 50.0,0.1), | ||
profit_stop_enable_pct: Phenotypes.RangeFactor(0.0, 5.0, 0.1), | ||
profit_stop_pct: Phenotypes.RangeFactor(0.0, 50.0, 0.1), | ||
|
||
// -- strategy | ||
rsi_periods: Phenotypes.Range(10, 30), | ||
stoch_periods: Phenotypes.Range(5, 30), | ||
stoch_k: Phenotypes.Range(1, 10), | ||
stoch_k_ma_type: Phenotypes.ListOption(['SMA','EMA','WMA','DEMA','TEMA','TRIMA','KAMA','MAMA','T3']), | ||
stoch_d: Phenotypes.Range(1, 10), | ||
stoch_k_sell: Phenotypes.RangeFactor(0.0, 100.0, 1.0), | ||
stoch_k_buy: Phenotypes.RangeFactor(0.0, 100.0, 1.0), | ||
stoch_d_ma_type: Phenotypes.ListOption(['SMA','EMA','WMA','DEMA','TEMA','TRIMA','KAMA','MAMA','T3']), | ||
|
||
|
||
|
||
bollinger_size: Phenotypes.RangeFactor(10, 25, 1), | ||
bollinger_updev: Phenotypes.RangeFactor(1, 3.0, 0.1), | ||
bollinger_dndev: Phenotypes.RangeFactor(1, 3.0, 0.1), | ||
bollinger_dType: Phenotypes.ListOption(['SMA','EMA','WMA','DEMA','TEMA','TRIMA','KAMA','MAMA','T3']), | ||
bollinger_upper_bound_pct: Phenotypes.RangeFactor(0.0, 100.0, 1.0), | ||
bollinger_lower_bound_pct: Phenotypes.RangeFactor(0.0, 100.0, 1.0) | ||
|
||
} | ||
} |
Oops, something went wrong.