Ichimoku Indicator
#1
Hey all,

I'm brand new to Gekko, but have some experience coding javascript. I'm looking to adapt the code found here (https://github.com/rd13/ichimoku) into a Gekko compatible indicator. For those that don't know, Ichimoku is a sort of "all in one" indicator system. Documentation is sparse, which while not ideal is ok because I don't mind investing the time. I've gotten as far as passing the candles into the generator function of the indicator, but I believe my issue now is my own ignorance of ECMA6 or the Gekko architecture.
 
If anyone is willing, I'd love to partner with someone to adapt this, as I think it would benefit the community as a whole and does not seem terribly difficult to do (even though I'm stuck!).

Respond here or shoot me a message if you're interested.

- Pat

p.s. Gekko looks great and I can't wait to start building strategies!
  Reply
#2
Update: I was actually able to work past my issue and have this working. I will post the indicator when I clean it up and add a few additional features (lagging span, etc).
  Reply
#3
Hi PatTrends,

I work too on a strategie based on Ichimoku.

This is base on the NPM package "Ichimoku" but the current version do not include "laggingspan" (chikou) who is a great indicator.

Here my starting code. Maybe somone can improve it.


First of all you have to install the npm package ichimoku on the root of the gekko folder :

Code:
npm install --save ichimoku

Then add the following file strategies/Ichimoku.js

Code:
var log = require('../core/log');
var config = require ('../core/util.js').getConfig();
var Ichimoku = require("ichimoku");

var strat = {};

// Prepare everything our method needs
strat.init = function() {
    this.ichimoku = new Ichimoku({
        conversionPeriod : this.settings.conversionPeriod,
        basePeriod       : this.settings.basePeriod,
        spanPeriod       : this.settings.spanPeriod,
        displacement     : this.settings.displacement,
        values           : []
    });

    this.requiredHistory = 82;
    this.oldIchimokuValue = null;
    this.ichimokuValue = null;
    this.wait_price_over_cloud = false;
    this.wait_price_under_cloud = false;
}

// What happens on every new candle?
strat.update = function(candle) {
    
    var updateIchimokuValue = this.ichimoku.nextValue({
       high  : candle.high,
       low   : candle.low,
       close : candle.close
   });
    
    
    this.oldIchimokuValue = (this.ichimokuValue ? this.ichimokuValue : null);
    this.ichimokuValue = {
        tenkan: (updateIchimokuValue ? updateIchimokuValue.conversion : 0),
        kijun: (updateIchimokuValue ? updateIchimokuValue.base : 0),
        spanA: (updateIchimokuValue ? updateIchimokuValue.spanA : 0),
        spanB: (updateIchimokuValue ? updateIchimokuValue.spanB : 0)
    }
    
}

strat.check = function() {

    // Check Kijun over Tenkan
    kijun_over_before_last = (this.oldIchimokuValue.tenkan >= this.oldIchimokuValue.kijun) ? false : true;
    kijun_over_last = (this.ichimokuValue.tenkan >= this.ichimokuValue.kijun) ? false : true;
    kijun_crossing_tenkan = (kijun_over_before_last == false && kijun_over_last == true) ? true : false;
    // Check Tenkan over Kijun
    tenkan_over_before_last = (this.oldIchimokuValue.kijun >= this.oldIchimokuValue.tenkan) ? false : true;
    tenkan_over_last = (this.ichimokuValue.kijun >= this.ichimokuValue.tenkan) ? false : true;
    tenkan_crossing_kijun = (tenkan_over_before_last == false && tenkan_over_last == true) ? true : false;

    var sell_signal = false;
    // SELL signal 1 : Kijun over Tenkan
    if((kijun_crossing_tenkan || this.wait_price_under_cloud)){
        if(this.candle.close < Math.max(this.ichimokuValue.spanA,this.ichimokuValue.spanB)){
            sell_signal = true;
            this.wait_price_over_cloud = false;
            this.wait_price_under_cloud = false;
            log.debug("[INFO] SELL signal - " + this.wait_price_under_cloud);
        }
        else{
            log.debug("[INFO] Kijun over Tenkan BUT wait price under the cloud");
            this.wait_price_under_cloud = true;
        }
        
    }
    // Add here other SELL signals
    // SELL actions
    if(sell_signal){    
        this.advice('short');
    }
    // Find BUY signals
    var buy_signal = false;
    // BUY signals 1 : Tenkan over Kijun and price over Span
    if((tenkan_crossing_kijun || this.wait_price_over_cloud)){
        if(this.candle.close > Math.max(this.ichimokuValue.spanA,this.ichimokuValue.spanB)){
            buy_signal = true;
            this.wait_price_over_cloud = false;
            this.wait_price_under_cloud = false;
            log.debug("[INFO] BUY signal");
        }
        /*
        else{
            log.debug("[INFO] Tenkan over Kijun BUT wait price over the cloud");
            this.wait_price_over_cloud = true;
        }
        */
    }
    // Add here other BUY signals
    // BUY actions
    if(buy_signal){        
        this.advice('long');
    }
}

module.exports = strat;

Then add the following file config/strategies/Ichimoku.toml

Code:
# Ichimoku settings
conversionPeriod = 9
basePeriod = 26
spanPeriod = 52
displacement = 26
  Reply
#4
Thank you Fizcko, this will be very helpful!

Correct me if I'm wrong, but I believe as far as the indicator portion goes, Lagging Span (Chikou Span) is just the candle close value. It would be up to the strategy to check if it is above or below price action 26 periods back. For the sake of completeness, I went ahead and made the following change to the generator function of the the npm Ichimoku script.
Code:
//Lagging Span is current candle close
       let lagging = tick.close;

       result = {
         conversion : parseFloat(conversionLine.toFixed(5)),
         base       : parseFloat(baseLine.toFixed(5)),
         spanA      : parseFloat(spanA.toFixed(5)),
         spanB      : parseFloat(spanB.toFixed(5)),
         lagging    : parseFloat(lagging.toFixed(5))
       }
  Reply
#5
(03-01-2018, 05:01 PM)Fizcko Wrote: Hi PatTrends,

I work too on a strategie based on Ichimoku.

This is base on the NPM package "Ichimoku" but the current version do not include "laggingspan" (chikou) who is a great indicator.

Here my starting code. Maybe somone can improve it.


First of all you have to install the npm package ichimoku on the root of the gekko folder :

Code:
npm install --save ichimoku

Then add the following file strategies/Ichimoku.js

Code:
var log = require('../core/log');
var config = require ('../core/util.js').getConfig();
var Ichimoku = require("ichimoku");

var strat = {};

// Prepare everything our method needs
strat.init = function() {
    this.ichimoku = new Ichimoku({
        conversionPeriod : this.settings.conversionPeriod,
        basePeriod       : this.settings.basePeriod,
        spanPeriod       : this.settings.spanPeriod,
        displacement     : this.settings.displacement,
        values           : []
    });

    this.requiredHistory = 82;
    this.oldIchimokuValue = null;
    this.ichimokuValue = null;
    this.wait_price_over_cloud = false;
    this.wait_price_under_cloud = false;
}

// What happens on every new candle?
strat.update = function(candle) {
    
    var updateIchimokuValue = this.ichimoku.nextValue({
       high  : candle.high,
       low   : candle.low,
       close : candle.close
   });
    
    
    this.oldIchimokuValue = (this.ichimokuValue ? this.ichimokuValue : null);
    this.ichimokuValue = {
        tenkan: (updateIchimokuValue ? updateIchimokuValue.conversion : 0),
        kijun: (updateIchimokuValue ? updateIchimokuValue.base : 0),
        spanA: (updateIchimokuValue ? updateIchimokuValue.spanA : 0),
        spanB: (updateIchimokuValue ? updateIchimokuValue.spanB : 0)
    }
    
}

strat.check = function() {

    // Check Kijun over Tenkan
    kijun_over_before_last = (this.oldIchimokuValue.tenkan >= this.oldIchimokuValue.kijun) ? false : true;
    kijun_over_last = (this.ichimokuValue.tenkan >= this.ichimokuValue.kijun) ? false : true;
    kijun_crossing_tenkan = (kijun_over_before_last == false && kijun_over_last == true) ? true : false;
    // Check Tenkan over Kijun
    tenkan_over_before_last = (this.oldIchimokuValue.kijun >= this.oldIchimokuValue.tenkan) ? false : true;
    tenkan_over_last = (this.ichimokuValue.kijun >= this.ichimokuValue.tenkan) ? false : true;
    tenkan_crossing_kijun = (tenkan_over_before_last == false && tenkan_over_last == true) ? true : false;

    var sell_signal = false;
    // SELL signal 1 : Kijun over Tenkan
    if((kijun_crossing_tenkan || this.wait_price_under_cloud)){
        if(this.candle.close < Math.max(this.ichimokuValue.spanA,this.ichimokuValue.spanB)){
            sell_signal = true;
            this.wait_price_over_cloud = false;
            this.wait_price_under_cloud = false;
            log.debug("[INFO] SELL signal - " + this.wait_price_under_cloud);
        }
        else{
            log.debug("[INFO] Kijun over Tenkan BUT wait price under the cloud");
            this.wait_price_under_cloud = true;
        }
        
    }
    // Add here other SELL signals
    // SELL actions
    if(sell_signal){    
        this.advice('short');
    }
    // Find BUY signals
    var buy_signal = false;
    // BUY signals 1 : Tenkan over Kijun and price over Span
    if((tenkan_crossing_kijun || this.wait_price_over_cloud)){
        if(this.candle.close > Math.max(this.ichimokuValue.spanA,this.ichimokuValue.spanB)){
            buy_signal = true;
            this.wait_price_over_cloud = false;
            this.wait_price_under_cloud = false;
            log.debug("[INFO] BUY signal");
        }
        /*
        else{
            log.debug("[INFO] Tenkan over Kijun BUT wait price over the cloud");
            this.wait_price_over_cloud = true;
        }
        */
    }
    // Add here other BUY signals
    // BUY actions
    if(buy_signal){        
        this.advice('long');
    }
}

module.exports = strat;

Then add the following file config/strategies/Ichimoku.toml

Code:
# Ichimoku settings
conversionPeriod = 9
basePeriod = 26
spanPeriod = 52
displacement = 26


Quote:  <-- POST /api/backtest
2018-03-09 09:19:02 (INFO):     Setting up Gekko in backtest mode
2018-03-09 09:19:02 (INFO):
2018-03-09 09:19:02 (INFO):     Setting up:
2018-03-09 09:19:02 (INFO):              Trading Advisor
2018-03-09 09:19:02 (INFO):              Calculate trading advice
2018-03-09 09:19:02 (INFO):              Using the strategy: Ichimoku
2018-03-09 09:19:02 (WARN):     TALIB indicators could not be loaded, they will be unavailable.
2018-03-09 09:19:02 (INFO):

2018-03-09 09:19:02 (INFO):     Setting up:
2018-03-09 09:19:02 (INFO):              Paper Trader
2018-03-09 09:19:02 (INFO):              Paper trader that simulates fake trades.
2018-03-09 09:19:02 (INFO):

2018-03-09 09:19:02 (INFO):     Setting up:
2018-03-09 09:19:02 (INFO):              Performance Analyzer
2018-03-09 09:19:02 (INFO):              Analyzes performances of trades
2018-03-09 09:19:02 (INFO):

2018-03-09 09:19:02 (INFO):             WARNING: BACKTESTING FEATURE NEEDS PROPER TESTING
2018-03-09 09:19:02 (INFO):             WARNING: ACT ON THESE NUMBERS AT YOUR OWN RISK!
/gekko/node_modules/sqlite3/lib/trace.js:27
                    throw err;
                    ^

TypeError: Reduce of empty array with no initial value
    at Array.reduce (<anonymous>)
    at _callee$ (/gekko/node_modules/ichimoku/lib/index.js:77:74)
    at tryCatch (/gekko/node_modules/regenerator-runtime/runtime.js:62:40)
    at Generator.invoke [as _invoke] (/gekko/node_modules/regenerator-runtime/runtime.js:296:22)
    at Generator.prototype.(anonymous function) [as next] (/gekko/node_modules/regenerator-runtime/runtime.js:114:21)
    at Ichimoku.nextValue (/gekko/node_modules/ichimoku/lib/index.js:148:26)
    at Base.strat.update (/gekko/strategies/Ichimoku.js:27:45)
    at Base.bound [as update] (/gekko/node_modules/lodash/dist/lodash.js:729:21)
    at Base.propogateTick (/gekko/plugins/tradingAdvisor/baseTradingMethod.js:218:8)
    at Base.bound [as propogateTick] (/gekko/node_modules/lodash/dist/lodash.js:729:21)
--> in Database#all('\n    SELECT * from candles_BTC_STRAT\n    WHERE start <= 1512818099 AND start >= 1512815100\n    ORDER BY start ASC\n  ', [Function])
    at Reader.get (/gekko/plugins/sqlite/reader.js:98:11)
    at Reader.bound [as get] (/gekko/node_modules/lodash/dist/lodash.js:729:21)
    at Market.get (/gekko/core/markets/backtest.js:61:15)
    at Market.bound [as get] (/gekko/node_modules/lodash/dist/lodash.js:729:21)
    at Market.processCandles (/gekko/core/markets/backtest.js:105:10)
    at bound (/gekko/node_modules/lodash/dist/lodash.js:729:21)
    at Statement.<anonymous> (/gekko/plugins/sqlite/reader.js:108:5)
  xxx POST /api/backtest 500 346ms -

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

Getting an error with a backtest. Any help?
  Reply
#6
2018-03-09 09:19:02 (WARN):     TALIB indicators could not be loaded, they will be unavailable.

You need to install TALIB.
Might as well also install tulip indicators while you are at it
npm i talib tulind
  Reply
#7
/*
Ichimoku Indicator ../strategies/indicators/ICHIMOKU.js
*/

var Indicator = function(){
this.input = 'candle';
this.highs = new Array(52);
this.lows = new Array(52);
this.age = 0;

this.tenkan = null;
this.kijun = null;
this.senkouSpanA = null;
this.senkouSpanB = null;
}

Indicator.prototype.update = function(candle) {
this.highs.push(candle.high);
this.lows.push(candle.low);
this.age++

if(this.age >= 52){
// Calc
this.tenkan = ( Math.max(...this.highs.slice(-9)) + Math.min(...this.lows.slice(-9)) ) / 2;
this.kijun = ( Math.max(...this.highs.slice(-26)) + Math.min(...this.lows.slice(-26)) ) / 2;
this.senkouSpanA = (this.tenkan + this.kijun) / 2;
this.senkouSpanB = ( Math.max(...this.highs.slice(-52)) + Math.min(...this.lows.slice(-52)) ) / 2;
}
}

module.exports = Indicator;




------------------------------------------------------------------------------------------------------------------------------------------------------
// . ./strategies/ICHIMOKU.js

var log = require('../core/log.js');

strat.init = function(){
// Add Ichimoku Indicator
this.addIndicator('ichimoku', 'ICHIMOKU');
}

strat.check = function(){
var ichimoku = this.indicators.ichimoku;

//ICHIMOKU INDICATOR
log.debug('ICHIMOKU INDICATOR');
log.debug('tenkan:', ichimoku.tenkan);
log.debug('kijun:', ichimoku.kijun);
log.debug('senkouSpanA:', ichimoku.senkouSpanA);
log.debug('senkouSpanB :', ichimoku.senkouSpanB );
log.debug('------------------------------------------');

}
  Reply
#8
anyone get this to work?
  Reply
#9
riesgo.rafael - The math in your indicator looks correct but I don't think it displaces spanA and SpanB (i.e. pushes the cloud in the future)?

Kris191 - Yes I have this working. I'll post an update soon. I've added a few other optional substrategies as well like "EMA as Tenkan-Sen" for slightly earlier tk crosses.
  Reply
#10
(03-20-2018, 09:36 PM)PatTrends Wrote: riesgo.rafael - The math in your indicator looks correct but I don't think it displaces spanA and SpanB (i.e. pushes the cloud in the future)?

Kris191 - Yes I have this working. I'll post an update soon. I've added a few other optional substrategies as well like "EMA as Tenkan-Sen" for slightly earlier tk crosses.

Hi,

I'm facing some issues running the code in particular:
Code:
2018-05-27 18:08:51 (INFO):    Setting up Gekko in backtest mode
2018-05-27 18:08:51 (INFO):    
2018-05-27 18:08:51 (INFO):    Setting up:
2018-05-27 18:08:51 (INFO):         Trading Advisor
2018-05-27 18:08:51 (INFO):         Calculate trading advice
2018-05-27 18:08:51 (INFO):         Using the strategy: ICHIMOKU
/home/full/gekko/strategies/ICHIMOKU.js:3
strat.init = function(){
^

ReferenceError: strat is not defined
   at Object.<anonymous> (/home/full/gekko/strategies/ICHIMOKU.js:3:1)
   at Module._compile (module.js:577:32)
   at Object.Module._extensions..js (module.js:586:10)
   at Module.load (module.js:494:32)
   at tryModuleLoad (module.js:453:12)
   at Function.Module._load (module.js:445:3)
   at Module.require (module.js:504:17)
   at require (internal/module.js:20:19)
   at Actor.setupTradingMethod (/home/full/gekko/plugins/tradingAdvisor/tradingAdvisor.js:48:16)
   at Actor.bound [as setupTradingMethod] (/home/full/gekko/node_modules/lodash/dist/lodash.js:729:21)
 xxx POST /api/backtest 500 1,268ms -

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

Could anybody help me?

Tks
  Reply


Forum Jump:


Users browsing this thread: