Gekko Strategy customization

Now that we’ve briefly seen how to install gekko and how to use its main functionalities, we will try to customize a first strategy.

As a first step, you need to review Gekko’s excellent standard documentation:

I won’t explain here all the functions used, since it is explained in the standard documentation, and you have links above. Neither will I explain how to code. Testing your strategy was explained before but here is a quick recap:

From the UI or from the CLI you can backtest a strategy or use a live traderPaper bot:

  • With the UI, the strategies in <gekko_installdir>/strategies will be proposed in the strategies dropdown list in the backtest page in the UI; also you need a .toml file with the parameters for your strategy in <gekko_installdir>/config/strategies
  • With UI and CLI, if you want to backtest, you need to have populated your database with datasets downloaded from markets
  • You may also want to run a livebot with the paperTrader activated to simulate a real trading bot on the live market; but I strongly suggest to backtest your strategy before as it will be much faster to test it on a huge amount of data, ie. a large timeframe of markets variations.

As we saw, strategies are stored in <gekko_installdir>/strategies, those are .js files. As we started previously by testing the MACD strategy, let’s take a look at it.

The out of the box MACD Gekko’s strategy

First we will work on a copy of the MACD, but we won’t modify it for now.

cp <gekko_installdir>/strategies/MACD.js <gekko_installdir>/strategies/MyMACD.js

In the init function, we can see a few variables being initialized:

  • A trend structure, which will be used by the strat to “remember” the past
  • The requiredHistory which is read from the configuration file config.js in the tradingAdvisor section
  • A call to the MACD indicator, which is by default stored in
    <gekko_installdir>/strategies/indicators

Now, let’s have a look at the MACD indicator: open
<gekko_installdir>/strategies/indicators/MACD.js

  • As we can see it will use the EMA.js indicator
  • It will define three EMAs, one with the short value defined in the configuration file config.js, another one with the long value, and the last one as the signal
  • The MACD indicator will:
    • Update the short and long EMAs with the market price (the last candle closure value, provided by the MACD strategy calling the MACD indicator)
    • Calculate the difference between them
    • Update the signal EMA by using the diff between short and long EMAs as input
    • Return the difference between the short/long EMA’s and the signal EMA to our strategy

Please, check some MACD documentation to better understand this logic.

Now that we know the basics of the MACD indicator (it takes 3 inputs and returns one value) let’s come back to our MyMACD strategy.

The log function will display some information in Gekko’s log at each candle update.

We can see that it creates an macd variable which will “point” to our macd indicator defined in the init function, and it will display the various results for the 3 EMA’s by using macd.short, macd.long, macd.signal, macd.diff, and macd.result which is the real output of the MACD indicator.

Now, the check function. This is the function where all the trading rules are implemented. What is does, basically:

  • If the MACD is upper than the up trend threshold in config.js, then (in a short way):
    • It checks if the number of iterations of up trend is superior to the historySize (which comes from config.js)
    • If yes and if we didn’t yet asked to BUY, it tries to BUY (long order)
  • Else, if the MACD is lower than the down trend threshold in config.js, then:
    • It checks if the number of iterations of low trend is superior to the historySize (which also comes from config.js)
    • If yes and if we didn’t yet asked to SELL, it tries to SELL (short order)
  • Else, and it means that the MACD result is between the down threshold and the up threshold, it does NOTHING.

This is how it performs on a long term Kraken/EUR/ETH dataset, with the standard parameters. I still use the MACD and not MyMACD as we didn’t modify MyMACD yet, nor we modified the config.js to use it.

Backtest Parameters

Results

As we can see, with some quick estimation of the parameters (6 hours candles + higher thresholds than for shorter candles), if we made no trades at all, we would have benefit 984% of evolution straight from the market, but with our 168 trades we earned less: 835% of gain.

Now let’s try to tweak it a little bit …

Parameters

Results

Quick analysis

Just by adjusting two or three parameters we gained in profit. Remember that this can’t be considered as a guarantee you will indeed earn assets or currency in “real life” on a live market; as here we tweak the model with data from the past. We have time to tweak it “as we want to see the result”. But we don’t know if the same parameters will perform well in the future.

If we zoom a little bit on the timeline, we can see that the strategy won’t perform so bad during high uptrends or downtrends. We can also see that it could be tweaked as we often see some LONG (buy) orders appearing just before a loss on the market, but followed by a SHORT (sell) orders. Or SELL orders just before a BUY, despite an uptrend market.

Conclusion: I’m not an expert, and I don’t know if we can rely on only one indicator. Litterature tends to prove that every market analysis needs to be double or triple checked with other indicators.

What is sure is that every indicator needs to be tweaked, and you need to analyse the market with other tools, more accurate, with a visual display of the indicators. I personally use kraken’s new Trading & Charting tool as well as other sites as TradingView.com. I first play globally with one indicator at a time, adjust the short/long parameters, study their crosses, and then study the difference between both, so that I can report what I think are good triggers in Gekko’s config.js thresholds. Then I backtest, as we will see much longer in another article.

Cloning the MACD strategy

So we copied <gekko_installdir>/strategies/MACD.js to <gekko_installdir>/strategies/MyMACD.js

For now we will just modify it a little bit, to later check we are using this strategy and not the stock MACD strat. Edit MyMACD.js and jump to line 51:

log.debug(‘calculated MyMACD properties for candle:’);
log.debug(‘\t’, ‘short:’, macd.short.result.toFixed(digits));
log.debug(‘\t’, ‘long:’, macd.long.result.toFixed(digits));

Save it, and thats all.

We also need to copy
<gekko_installdir>/config/strategies/MACD.toml to
<gekko_installdir>/config/strategies/MyMACD.toml so that the backtest UI can display customized parameters for the MyMACD settings.

Now we need to modify
<gekko_installdir>/config.js so that Gekko will use it.

First the trading.advisor plugin needs to be modified to call the right strategy. It’s just the name of your strategy.js file, without the .js extension.

config.tradingAdvisor = {
enabled: true,
method: ‘MyMACD‘,
candleSize: 360, //to reflect the 6 hours candle I used in previous backtest
historySize: 6, //to reflect the 6 candles of warmup period in backtest UI
}

Then we need to provide the tradingAdvisor some parameters:

// MACD settings:
config.MyMACD = {
// EMA weight (α)
// the higher the weight, the more smooth (and delayed) the line
short: 10,
long: 21,
signal: 9,
// the difference between the EMAs (to act as triggers)
thresholds: {
down: -0.7,
up: 0.3,
// How many candle intervals should a trend persist
// before we consider it real?
persistence: 0
}
};

Those 2 modifications will allow use to use our strat with Gekko’s CLI.

Next, in case we want to use the UI to backtest or run a livebot, we also edit <gekko_installdir>/config/strategies/MyMACD.toml

short = 10
long = 21
signal = 9

[thresholds]

down = -0.7
up = 0.3
persistence = 0

Let’s test it on the UI.

Woohoo, same result :] Just to be absolutely sure we now use MyMACD and not MACD, let’s run it through the CLI and check the console or logs:

gekko@HP850G3:~/gekko$ node gekko –config config.js –backtest



2019-01-09 14:07:52 (DEBUG): calculated MyMACD properties for candle:
2019-01-09 14:07:52 (DEBUG): short: 247.91113481
2019-01-09 14:07:52 (DEBUG): long: 253.43444971
2019-01-09 14:07:52 (DEBUG): macd: -5.52331490
2019-01-09 14:07:52 (DEBUG): signal: -4.87686289
2019-01-09 14:07:52 (DEBUG): macdiff: -0.64645201
2019-01-09 14:07:52 (DEBUG): In no trend
2019-01-09 14:07:52 (DEBUG): calculated MyMACD properties for candle:
2019-01-09 14:07:52 (DEBUG): short: 249.96729212
2019-01-09 14:07:52 (DEBUG): long: 253.96040883
2019-01-09 14:07:52 (DEBUG): macd: -3.99311671
2019-01-09 14:07:52 (DEBUG): signal: -4.70011365
2019-01-09 14:07:52 (DEBUG): macdiff: 0.70699694
2019-01-09 14:07:52 (DEBUG): In uptrend since 1 candle(s)
2019-01-09 14:07:52 (INFO): 2017-10-24 07:29:00: Paper trader simulated a BUY 0.00000000 EUR => 3.39807550 ETH

As you already figured out, we can see the modification we made in MyMACD.js, so YES, this is the right strategy we are using. Now we can try to modify it, as a quick example.

Customizing our strategy

One thing which is not covered in this strategy is the “notrend” possibility. When the MACD result stalls for a long time between our down and up thresholds, it doesn’t mean that the market and currency/asset rates are stables. It means that it is not moving enough up or down to be used by our strategy.

But, the market can still decrease (or increase) and maybe after a few candles we should sell, to keep our gains by converting back our assets in currency. This is called a stoploss.

So basically we should and will:

  1. Introduce a new parameter in the conf, called stoploss
  2. Add the handling of the stoploss in the “notrend” section of the strategy: if the closing price of the candle we are reviewing is below our “last buy price” then we order Gekko to advice a short position (sell).
  3. So we will also need to modify the uptrend section, to update the stoploss price if the market is uptrend.

Note that there are other ways to do that, we could also add a OR condition to the downtrend section, to check if (MACD diff is below down_threshold OR if candle.price < stoploss_price).

Adding a new parameter in conf

Edit <gekko_installdir>/config.js

config.MyMACD = {
// EMA weight (α)
// the higher the weight, the more smooth (and delayed) the line
short: 10,
long: 21,
signal: 9,
// the difference between the EMAs (to act as triggers)
thresholds: {
down: -0.7,
up: 0.3,
stoploss: 10,
// How many candle intervals should a trend persist
// before we consider it real?
persistence: 0
}
};

Now edit
<gekko_installdir>/strategies/MyMACD.js

In the init block, we add this. Note that if you define a variable or const in the init() block, it won’t be persisted in the check() block. So we use “this” object to store data.

//get the stoploss rate from conf
this.stoploss_rate = this.settings.thresholds.stoploss;
//reset the stoploss_price
this.stoploss_price = “”;

We need to modify the check function so that it will receive the candle description as input, as we will need to use it to get the candle.price we try to buy, or the candle.price to update the stoploss if the market is uptrend.

method.check = function(candle) {

In the uptrend section, we add this, to update the new stoploss price each time we sell and each time the market is increasing if it’s new price is higher than our stoploss_price:

log.debug(‘In uptrend since’, this.trend.duration, ‘candle(s)’);

if (this.stoploss_price != “” && candle.close > this.stoploss_price)
{
this.stoploss_price = candle.close-candle.close*this.stoploss_rate/100;
log.info(‘===> New computed stoploss price is:’, this.stoploss_price,'<===’);
}


if(this.trend.persisted && !this.trend.adviced) {
this.trend.adviced = true;
this.advice(‘long’);
this.stoploss_price = candle.close-candle.close*this.stoploss_rate/100;

log.info(‘===> We BOUGHT at ~’,candle.close,’ and computed stoploss price is:’, this.stoploss_price,'<===’);
} else
this.advice();

Now in the downtrend section, if we SELL, we should reset the stoploss_price as we don’t own any assets anymore.

if(this.trend.persisted && !this.trend.adviced) {
this.trend.adviced = true;
this.advice(‘long’);
this.stoploss_price = candle.close-candle.close*this.stoploss_rate/100;
log.info(‘===> We BOUGHT at ~’,candle.close,’ and computed stoploss price is:’, this.stoploss_price,'<===’);

} else
this.advice();

Let’s give it a try, just to make sure we didn’t break anything yet; and even if we actually did not change anything to the decision tree to sell or buy.

node gekko –config config.js –backtest

So what do we see ?

  • First, that I disabled the debug mode at the beginning of the config.js file and I forgot to write it here 🙂
  • The first BUY displayed has initialized the stoploss_price by computing the stoploss_rate we defined in conf
  • Then the stoploss_price keeps rising, as we took care to not update it if the market price was lower than our stoploss_price
  • When we SELL, the stoploss_price is resetted
  • Seems all good so far !

Now let’s modify the “notrend” block and create a “stall” trend with a SELL if we detect a persistence and a market price lower than our stoploss_price.

} else {
//log.debug(‘In no trend’);

// new trend detected
if(this.trend.direction !== ‘stall’)
// reset the state for the new trend
this.trend = {
duration: 0,
persisted: false,
direction: ‘stall’,
adviced: false
};

this.trend.duration++;

log.debug(‘In stalled trend since’, this.trend.duration, ‘candle(s)’);

if(this.trend.duration >= this.settings.thresholds.persistence)
this.trend.persisted = true;

if (this.trend.persisted && !this.trend.adviced)
{
if (this.stoploss_price != “” && candle.close < this.stoploss_price) { this.trend.adviced = true; this.advice(‘short’); this.stoploss_price = “”; log.info(‘===> We \’Stalled\’ SOLD at ~’,candle.close,’ and reseted stoploss price. <===’);

}

log.info(‘===> Market not low enough to \’stall\’ sell <===’);
}

this.advice();
}

Beware that we also need to modify the downtrend block condition, as we don’t need it to SELL another time if the market is really downtrend, after we already sold earlier thanks to our new “stall trend” code:

} else if(macddiff < this.settings.thresholds.down && this.stoploss_price != “”) {

And we test it (note that I commented out the last log.info line in the Stall block to reduce verbosity):

It seems to work. Don’t forget to copy the MACD.toml file in a new MyMACD.toml file and to add the stoploss parameter, so you can use it in the backtest UI.

Conclusion and other possible improvements

Conclusion

So how does it perform ? Well, not so good 🙂 I will write another post about backtesting, and how to try to tune the parameters. Because, As we already noticed, tweaking the parameters does require a lot of analysis, and a lot of tests.

Here we just introduced a new parameter, and here is the result, knowing that I kept the previous test parameters.

So “out of the box” our new strategy is less efficient than the stock MACD. But we gained control over a new kind of trend on the market watched by the Strat. We need to tune it and find better values for the parameters. Maybe the code also needs to be optimized, I don’t pretend AT ALL to have a good knowledge of the good rules to code.

In a next article, I will explain how I managed to launch a massive test with randomized (or not) parameters, in order to track the best results (on past data, again), using public tools from contributors.

For information, one backtest with this strategy, on my i7 “mid class office” laptop approximately runs during 41 seconds, after I modified all the log.info() functions we used above to use log.debug() instead; and with debug mode unactivated in config.js.

This was just an example to explain how to instantiate and modify a strategy. I don’t pretend this modification to be a gain. Again, this is at your own risk, from running a non optimized standard gekko’s Strat, to running a customized strategy. You will probably loose your investment as there is no magic possible, it means it is not possible to anticipate the markets without a huge risk, or a very high confidence in your markets knowledge.

Ideas for more improvements

Other possible improvements you could work on are:

  • Add a parameter in conf to provide your strategy the last type of order (buy or sell) with its price so that your strategy will be able to use it for its first decision
  • Calculate the stoploss in the init section if the last action in conf was a buy and you know its price, so that you won’t miss to sell if the very first trend your strategy will have to deal with is a long stall-but-decreasing-market.
  • Deal with more indicators than just the MACD.
  • Port the stoploss principle to buy actions if we are on a long but slow persisted market raise,
  • What is currently not allowed in Gekko is to handle multiple candle size at the same time, so that you could have one indicator working on short terms trends, and another one on long term trends, and take decisions based on the two (or N candle sizes). There are some forks allowing it, but I didn’t give it a try yet.

3 thoughts on “Gekko Strategy customization

  1. Hey, i just want you to know, that i love the idea what you are doing. But you have a mistake in the section where you explain the sell function. There is the same code as in the long position.
    Maybe you can help me with that ;D

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.