askmike / gekko

A bitcoin trading bot written in node - https://gekko.wizb.it/
MIT License
10.07k stars 3.94k forks source link

[Community Request] Custom strategies #1263

Closed Gab0 closed 6 years ago

Gab0 commented 7 years ago

I'm developing a genetic algorithm approach to boost Gekko strategies parameters. So far some good results, but not as good as expected.. Would be nice to test it with more complex strategies, that takes in a big number of parameters; Then I ask this community... (hehe) Anyone has made a good, complex, functional and shareable strategy? Thanks..

askmike commented 7 years ago

ping @generalectric @thegamecat

generalectric commented 7 years ago

The more complex I've written my strats with multiple indicators and take a ton of settings I have run for a week through GA to get moderate results... Where the simplest strats blow them out of the water within hours in GA backtesting. I really dont have anything I can share as I feel my more complex strats are a better example of what NOT to do. Keeping the strats short and simple is better from my experience.

thegamecat commented 7 years ago

Agree with a lot of what Gen says, however, if you consider what "a threshold is" you can extend the role of the GA to be as wide as you like.

Test and learn.

Gab0 commented 7 years ago

This info seems correct, but I think the ideal level of complexity is somewhere a little above current strategies. A sum of like two of the stock strategies might do good. The thresholds are important to mess around, but a too wide margin will just produce parameter values outside the 'this works' area, and this margin seems small... I'm here talking about custom strategies because I stumbled on a problem with my GAs: if a strategy with some parameters do good on a 'uprising price' region of the datasets, it will fail hard on misery times of bitcoin prices; and vice versa. This always happens, seems to be a symptom of too simple strategy.

generalectric commented 7 years ago

@Gab0, I agree and THIS is the problem i have. Using a GA optimized strat just finds the average settings that produce the best results overall. Even if you have settings for up and down in small candles there is still the bigger picture of what is going on with the big candles. If we could get big candle data in our small candle strats then we could have optimized settings for the up down and the ranging market trends meaning small candle strat would now have optimized up and down settings for each of big candle up, down, and flat or ranging markets. One way to do this would be having the ability to have 2 candle sizes in a strat... another possibility is running a strat as a child process of a master or parent strat. Obviously the first way would be my choice.... but that is up for debate. The latter should work in theory provided we could get the trade data emitted through the parent strat so as to maintain backtestability and usage with the ui and charting etc.

edit Oooooor better yet... Have small candles be the main trading process... while running a child process using large candles and have it pass the data back to the parent small candle process

generalectric commented 7 years ago

Ok so I got it working... its actually pretty straightforward and simple. Just spawn a child process with IPC and ignored stdio. Then process.send() the data... and on.message function to process the recieved data into variables then used by the parent strategy. This should work fine for a live gekko as is... I do however worry about race conditions for backtesting and I'm thinking I will need to return candle data to make sure candle dates are in fact.. in sync... or try to anyways. I'll cross that bridge when I get there.

Gab0 commented 7 years ago

These are modifications on gekko engine itself or done inside a strategy? If we could just pass candleSizes as a tuple to do this magic would be really nice heh. Anyway it seems a good idea, looking forward for the new branch so I can test..

generalectric commented 7 years ago

Its done in strat. Like I said I'm not really a fan of it... it DOES get the job done... though this can probably be done WAY better. I was hoping @askmike would chime in with a better direction so for now this is the quickest easiest hacky way to make what I personally need. I'll share a generic strat like the stock macd one with this implimented in a gist when I get some time to finish it off.

Gab0 commented 7 years ago

I think every strategy would benefit from this. So it should be put on Gekko itself. But each strategy would have their own way of weigthing the longer candle results... its hard to get to the best way to implement this indeed. So yeah we try on one strat and see what happens..

generalectric commented 7 years ago

This is really simple to implement. Here is a gist with instructions https://gist.github.com/generalectric/578eae050393986ff96951c92722070d

edit FYI, just as I suspected, I nearly doubled my profit using this... and its not over yet, GA is still running I am expecting to juice it a little bit more

Gab0 commented 7 years ago

@generalectric That's a good strategy.. I managed to avoid new node gekko.js calls by modifying tradingAdvisor.js.

tradingAdvidor.js line 78 ~117


//setup everything a child strategy needs, and that is the same stuff the main strat gets,
// except relayAdvice binding;

if(config.tradingAdvisor.childStrategy.enabled) { this.childStrategy=true; var childConfig = config.tradingAdvisor.childStrategy;

if(!fs.existsSync(dirs.methods + childConfig.method + '.js')) util.die('Gekko can\'t find the child strategy "' + childConfig.method + '"'); var childMethod = require(dirs.methods + childConfig.method); var childConsultant = require('./baseTradingMethod');

_.each(childMethod, function(fn, name) { childConsultant.prototype[name] = fn; });

if(config[childConfig.method]) {
    var childTradingSettings = config[childConfig.method];
}

else util.die("Child method config not found!")

this.childMethod = new childConsultant(childTradingSettings); this.childBatcher = new CandleBatcher(childConfig.candleSize); this.childBatcher.on('candle', this.childMethod.tick); //childMethod won't pass advice; }

}

// HANDLERS // process the 1m candles Actor.prototype.processCandle = function(candle, done) { if (this.childStrategy) { this.childBatcher.write([candle]); this.method.childInfo = this.childMethod.result; } this.batcher.write([candle]); done(); }

>config.js

config.tradingAdvisor = { enabled: true, method: 'DEMA', candleSize: 1, historySize: 3, adapter: 'sqlite', childStrategy : { enabled: true, candleSize: 10, method: 'cMACD', }, .....

I have not tested it yet because I can't imagine how a strategy could read the child strategy properly :c..
>Children strats store values as you sugested

this.result['macd'] = this.indicators.macd.result; this.result['rsi'] = this.indicators.rsi.result;


That will be passed to main strategy as .childInfo before each tick.
Dunno, test it or show me how we use child strat info ^^
Nickduino commented 6 years ago

The more complex I've written my strats with multiple indicators and take a ton of settings I have run for a week through GA to get moderate results... Where the simplest strats blow them out of the water within hours in GA backtesting. I really dont have anything I can share as I feel my more complex strats are a better example of what NOT to do. Keeping the strats short and simple is better from my experience.

Can you share the short strategies, then? :-)

stale[bot] commented 6 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. If you feel this is very a important issue please reach out the maintainer of this project directly via e-mail: gekko at mvr dot me.