[SHARE] Simple RSI BULL/BEAR strategy
#21
(02-03-2018, 09:48 PM)SettusBlake Wrote: Hello! (First post for me here)

I tried your strategie, but got this error:

Code:
2018-02-03 22:44:49 (INFO):     Setting up Gekko in backtest mode
2018-02-03 22:44:49 (INFO):
2018-02-03 22:44:49 (INFO):     Setting up:
2018-02-03 22:44:49 (INFO):              Trading Advisor
2018-02-03 22:44:49 (INFO):              Calculate trading advice
2018-02-03 22:44:49 (INFO):              Using the strategy: RSI_BULL_BEAR
2018-02-03 22:44:49 (WARN):     TALIB indicators could not be loaded, they will be unavailable.
2018-02-03 22:44:49 (WARN):     TULIP indicators could not be loaded, they will be unavailable.
 xxx POST /api/backtest 500 252ms -

 Error: non-error thrown: Child process has died.
     at Object.onerror (/home/unix/gekko/node_modules/koa/lib/context.js:105:40)
     at <anonymous>
     at process._tickCallback (internal/process/next_tick.js:188:7)

You need to install the tulip indicators
  Reply
#22
hi, 
first.. thanks a lot for this interesting strategy.. 
i am trying to use it, and every file is in the right folder, I also can see the strategy and the settings in the main Gekko page... 
but when I click Backtesting it doesn't work... 
it just loads and stops.. 

what am I doing wrong? 
should I stop and start Gekko? or where is the problem?

thanks. 
Big Grin

(02-04-2018, 03:49 AM)Derbeweis Wrote: hi, 
first.. thanks a lot for this interesting strategy.. 
i am trying to use it, and every file is in the right folder, I also can see the strategy and the settings in the main Gekko page... 
but when I click Backtesting it doesn't work... 
it just loads and stops.. 

what am I doing wrong? 
should I stop and start Gekko? or where is the problem?

thanks. 
Big Grin

i solved it.. I didn't have the indicators Libraries installed yet... 
hat to do: 
Code:
npm install tulind

npm install talib

now it works... looks very very interesting.. 
thanks
  Reply
#23
Yes, should be added to the instructions.. i just assumed everyone had installed the indicators since they are pretty much needed for most custom strategies.
  Reply
#24
(02-04-2018, 07:18 AM)tommiehansen Wrote: Yes, should be added to the instructions.. i just assumed everyone had installed the indicators since they are pretty much needed for most custom strategies.

Can you help.me create a strategy for gekko ?
  Reply
#25
@tommiehansen again.. thanks for your effort here it looks very interesting... I am still backtesting it against different combinations with different configuration.... I may even start a real test tomorrow.. 
but I still have some Qs/Ideas?

1. Stoploss: 
could we build a general Stoploss that will end any round that goes to a constant % of loss (for example, don't loose more than 5% or 3% per trade)

2. Exchange/Margin?
will this work with exchanges that only trade what you have without margin? like Binance for example? 
for example if you trade BTC/USDT and starting with 100$ you can't short BTC, you just can buy and then sell... so will it work on that kind of trades or not?

thanks again...
  Reply
#26
1. Already implemented and tested. Did not improve performance but in all tests made the performance worse so it was removed.
Also implemented a 'take profit' but this was also removed since it also didn't do anything except worsen the performance.

What ended up happening was basically this:
a. Buy
b. It was a bad buy (stoploss was met) so SELL
...
c. But RSI is even lower now so BUY again = better performance
--OR--
d. Do nothing and miss the opportunity = worse performance

Often it was the D-condition that happend which is suboptimal since it just ends up resulting in a lot of missed opportunities.
It might differ if one tests with 1-minute candles though, but testing is glacially slow so don't have time to test everything.

I created a generic function for stoploss though:

Code:
    /* STOPLOSS */
    stoploss: function( maxDiff, cur, old )
    {
    
        let diff = ((cur/old)-1) * 100;
            diff = diff.toFixed(2),
            ret = false;
        
        if( maxDiff >= diff )
        {
            ret = true;
            let str = 'Stoploss hit! Stoploss @ ' + maxDiff + '% Current diff: ' + diff + '%';
            log.debug(str);
        }
        
        return ret;
    },


It just returns TRUE or FALSE if condition is met.
One would have to set a param to save 'old' (what price one bought at) as well etc.



Do also note that the strategy already has a stoploss of sorts due to the switching of trends. If BULL buys @ RSI 50 and BEAR sells at RSI 50 the BEAR-trend will basically act as a stoploss (which is part of the idea). So that thing already works as intended.

2. I do not know, this just go long and short. This is more of a genereal Gekko-question?
  Reply
#27
(02-04-2018, 03:09 PM)tommiehansen Wrote: 1. Already implemented and tested. Did not improve performance but in all tests made the performance worse so it was removed.
Also implemented a 'take profit' but this was also removed since it also didn't do anything except worsen the performance.

What ended up happening was basically this:
a. Buy
b. It was a bad buy (stoploss was met) so SELL
...
c. But RSI is even lower now so BUY again = better performance
--OR--
d. Do nothing and miss the opportunity = worse performance

Often it was the D-condition that happend which is suboptimal since it just ends up resulting in a lot of missed opportunities.
It might differ if one tests with 1-minute candles though, but testing is glacially slow so don't have time to test everything.

I created a generic function for stoploss though:

Code:
    /* STOPLOSS */
    stoploss: function( maxDiff, cur, old )
    {
    
        let diff = ((cur/old)-1) * 100;
            diff = diff.toFixed(2),
            ret = false;
        
        if( maxDiff >= diff )
        {
            ret = true;
            let str = 'Stoploss hit! Stoploss @ ' + maxDiff + '% Current diff: ' + diff + '%';
            log.debug(str);
        }
        
        return ret;
    },


It just returns TRUE or FALSE if condition is met.
One would have to set a param to save 'old' (what price one bought at) as well etc.



Do also note that the strategy already has a stoploss of sorts due to the switching of trends. If BULL buys @ RSI 50 and BEAR sells at RSI 50 the BEAR-trend will basically act as a stoploss (which is part of the idea). So that thing already works as intended.

2. I do not know, this just go long and short. This is more of a genereal Gekko-question?

ok looks interesting.. I was just thinking about minimising the Loss trades... so it could never be a loss more than 5%, but I understand what you say... 

about the 2. Question... that will be very interesting... any one from Gekko interested to answer?
  Reply
#28
Added backtest for NEO-USDT.

Began working with an alternative that uses MA for RSI in order to smooth out the values.
So far it really hasn't worked out that great or given any increased benefits but further testing would be needed.

A generic SMA function was written which might be useful for someone:


Code:
var strat = {

    /* your init... */
    init: function() {},

    /* simple moving average (for any values) : returns current average for 'name' */
    sma: function(name, price, points)
    {
        // create arr if not exist + generate array
        if( !this[name] )
               {
            let a = 0,     b = [];
            for (a; a < points; a++) { b[a] = 0; }
            this[name] = b;
        }

        let arr = this[name],
            len = arr.length;

        arr[len] = price; // add new to last in array
        arr.shift(); // remove first (old) from array (keeping max order)        
        this[name] = arr; // set/save

        // calculate current average
        let i = 0,
             total = 0;

        for( i; i < len; i++ ) { total += arr[i]; }
     
        let avg = total / len;
        return avg;
    },

    // your check
    check: function() {}

    // your end
    end: function() {}

}

Just supply it with name, price (candle.close etc) and points (number of points to use).
  Reply
#29
Hi Tommie
when i was looking at the Indicators at Coinigy, with Usdt/NEO, i recognized:
if after trend reversal, in the Bull-Trend, the Buy-Volume does fall back to more normal.
then the Bull_RSI_high could never be reached.
So i added a second Qualification that only apply in the Bull-Trend by using RateOfChange (ROC) indicator.
(the last version with PPO did not work because of human error).

With Neo the result is pretty good when backtesting January.

Im new to code so please let me know if i should erase this post. Again thanks alot

The ROC indicator behaves not as expected:
ROC-level: Coinigy shows a level of >4 for the Neo Bull Trend but for the strat eny other value else than 0, creates negative Results.
ROC-length works well.

Code:
/*
   RSI Bull and Bear
   Use different RSI-strategies depending on a longer trend
   3 feb 2017
   
   (CC-BY-SA 4.0) Tommie Hansen
   https://creativecommons.org/licenses/by-sa/4.0/
*/

// req's
var log = require ('../core/log.js');
var config = require ('../core/util.js').getConfig();

// strategy
var strat = {
   
   /* INIT */
   init: function()
   {
       this.name = 'RSI Bull and Bear';
       this.requiredHistory = config.tradingAdvisor.historySize;
       this.resetTrend();
       
       // debug? set to flase to disable all logging (improves performance)
       this.debug = false;
       
       // add indicators
       this.addTulipIndicator('maSlow', 'sma', { optInTimePeriod: this.settings.SMA_long });
       this.addTulipIndicator('maFast', 'sma', { optInTimePeriod: this.settings.SMA_short });
       this.addTulipIndicator('BULL_RSI', 'rsi', { optInTimePeriod: this.settings.BULL_RSI });
       this.addTulipIndicator('IDLE_RSI', 'rsi', { optInTimePeriod: this.settings.IDLE_RSI });
       this.addTulipIndicator('BEAR_RSI', 'rsi', { optInTimePeriod: this.settings.BEAR_RSI });
       this.addTulipIndicator('ROC_val', 'roc', { optInTimePeriod: this.settings.ROC });
       
       // debug stuff
       this.startTime = new Date();
       this.stat = {
           bear: { min: 100, max: 0 },
           bull: { min: 100, max: 0 },
           idle: { min: 100, max: 0 }
       };
       
       
   }, // init()
   
   
   /* RESET TREND */
   resetTrend: function()
   {
       var trend = {
           duration: 0,
           direction: 'none',
           longPos: false,
       };
   
       this.trend = trend;
   },
   
   /* get lowest/highest for backtest-period */
   lowHigh: function( rsi, type )
   {
       let cur;
       if( type == 'bear' ) {
           cur = this.stat.bear;
           if( rsi < cur.min ) this.stat.bear.min = rsi; // set new
           if( rsi > cur.max ) this.stat.bear.max = rsi;
       }
       else if( type == 'idle') {
       cur = this.stat.idle;
       if( rsi < cur.min ) this.stat.idle.min = rsi; // set new
       if( rsi > cur.max ) this.stat.idle.max = rsi;    
       }
       
       else {
           cur = this.stat.bull;
           if( rsi < cur.min ) this.stat.bull.min = rsi; // set new
           if( rsi > cur.max ) this.stat.bull.max = rsi;
       }
   },
   
   
   /* CHECK */
   check: function()
   {
       if( this.candle.close.length < this.requiredHistory ) { return; } // check if candle length is correct
       
       // get all indicators
       let ind = this.tulipIndicators,
           maSlow = ind.maSlow.result.result,
           maFast = ind.maFast.result.result,
           rsi,
           ROC_val = ind.ROC_val.result.result;
           
       // BEAR TREND
       if( maFast < maSlow )
       {
           rsi = ind.BEAR_RSI.result.result;
           if( rsi > this.settings.BEAR_RSI_high ) this.short();
           else if( rsi < this.settings.BEAR_RSI_low ) this.long();            
           if(this.debug) this.lowHigh( rsi, 'bear' );
           //log.debug('BEAR-trend');
       }

       // BULL TREND
       else
       {
           // IDLE-BULL OR REAL-BULL TREND ??
           if( ROC_val <= this.settings.ROC_lvl )
           {
               // BULL-IDLE TREND
               rsi = ind.IDLE_RSI.result.result;
               if( rsi > this.settings.IDLE_RSI_high ) this.short();
               else if( rsi < this.settings.IDLE_RSI_low )  this.long();
               if(this.debug) this.lowHigh( rsi, 'idle' );
               //log.debug('IDLE-trend');
           }
           // REAL BULL TREND
           else
           {
               rsi = ind.BULL_RSI.result.result;
               if( rsi > this.settings.BULL_RSI_high ) this.short();
               else if( rsi < this.settings.BULL_RSI_low )  this.long();
               if(this.debug) this.lowHigh( rsi, 'bull' );
               //log.debug('BULL-trend');
           }
           
       }
   
   }, // check()
   
   
   /* LONG */
   long: function()
   {
       if( this.trend.direction !== 'up' ) // new trend? (only act on new trends)
       {
           this.resetTrend();
           this.trend.direction = 'up';
           this.advice('long');
           //log.debug('go long');
       }
       
       if(this.debug)
       {
           this.trend.duration++;
           log.debug ('Long since', this.trend.duration, 'candle(s)');
       }
   },
   
   
   /* SHORT */
   short: function()
   {
       // new trend? (else do things)
       if( this.trend.direction !== 'down' )
       {
           this.resetTrend();
           this.trend.direction = 'down';
           this.advice('short');
       }
       
       if(this.debug)
       {
           this.trend.duration++;
           log.debug ('Short since', this.trend.duration, 'candle(s)');
       }
   },
   
   
   /* END backtest */
   end: function(){
       
       let seconds = ((new Date()- this.startTime)/1000),
           minutes = seconds/60,
           str;
           
       minutes < 1 ? str = seconds + ' seconds' : str = minutes + ' minutes';
       
       log.debug('Finished in ' + str);
       
       if(this.debug)
       {
           let stat = this.stat;
           log.debug('RSI low/high for period:');
           log.debug('BEAR low/high: ' + stat.bear.min + ' / ' + stat.bear.max);
           log.debug('BULL low/high: ' + stat.bull.min + ' / ' + stat.bull.max);
           log.debug('IDLE low/high: ' + stat.idle.min + ' / ' + stat.idle.max);
       }
   }
   
};

module.exports = strat;

Code:
# SMA Trends
SMA_long = 800
SMA_short = 40

# BULL
BULL_RSI = 10
BULL_RSI_high = 80
BULL_RSI_low = 50

# IDLE
IDLE_RSI = 12
IDLE_RSI_high = 65
IDLE_RSI_low = 39

# BEAR
BEAR_RSI = 15
BEAR_RSI_high = 50
BEAR_RSI_low = 25

# ROC
ROC = 6
ROC_lvl = 0

# BULL/BEAR is defined by the longer SMA trends
# if SHORT over LONG = BULL
# if SHORT under LONG = BEAR

# ROC is the LENGHT (averaging)
# Leave ROC_lvl at 0 otherwise Results are negative



Attached Files
.png   gekkoIDLE_2.png (Size: 156.19 KB / Downloads: 205)
  Reply
#30
Thanks for sharing Tommie. This works better than all of my attempts put together!

susitronix - the Idle trend looks like a good addition at first glance, I'll have a play Smile
  Reply


Forum Jump:


Users browsing this thread: