Genetic Optimization



  • Is there any plan to incorporate genetic (or similar) algorithms to optimize a strategy?

    I have 2 parameters I need to test with ranges from 1-200 (i'm not overoptimizing/curvefitting) and the brute force method takes forever on a laptop.

    For reference: http://outlace.com/Simple-Genetic-Algorithm-in-15-lines-of-Python/

    btw, loving the platform so far! nice work



  • It would be great if genetic optimization can be implemented.

    In order to avoid long waiting now , I usually do draft optimization with larger parameter steps (say not 1, but 5), identify interesting local areas, and then run detailed optimization with the small step on the local, smaller than original area. This might help.


  • administrators

    Adding a use case to support uses cases which don't simply go over the entire range of parameters could be considered.

    The question is:

    • how does one decide if a given parameter combination is the path to follow?

    Some options:

    • Greater total value
    • Larger Sharpe Ratio
    • Many others

    Some of the analyzers return dict which contain for example datetime timestamps and returns (for a given timeframe) and the core code cannot consider analyzers that people may plug in with unknown values.

    Some kind of callback would have to be implemented in each strategy to return a score.



  • @backtrader It would be useful to have an ability to use output from any analyzer of the strategy as a goal for optimization and then set an action - maximize it or minimize it.



  • @backtrader

    @backtrader said in Genetic Optimization:

    Adding a use case to support uses cases which don't simply go over the entire range of parameters could be considered.

    The question is:

    • how does one decide if a given parameter combination is the path to follow?

    Some options:

    • Greater total value
    • Larger Sharpe Ratio
    • Many others

    Some of the analyzers return dict which contain for example datetime timestamps and returns (for a given timeframe) and the core code cannot consider analyzers that people may plug in with unknown values.

    Some kind of callback would have to be implemented in each strategy to return a score.

    yes - Genetic Optimizers (or any other optimization algorithm) need a 'reward' function... the output from an Analyzer would be a natural fit for this. Time frame should be the entire run of the strategy, unless it's a walk-forward optimization (which is possibly a different discussion altogether).

    In another platform I use - ninjatrader - reward functions are customizable (via C# code) using strategy performance outputs. The reward type is passed to the optimizer as a parameter at execution. Time frames are not allowed in reward functions since the time period to optimize and the days to test out-of-sample are also passed as parameters to the optimizer.

    Not sure how all that would translate to the backtrader framework, but this would be key in backtesting a strategy imo.


  • administrators

    The difference being that in backtrader the analyzers are plugged by the user and there cannot be an incredibly wise function to understand how to evaluate each possible combination of analyzers.

    One possible way would be to implement the reward/scoring mechanism by means of an analyzer. This is possible because analyzers can host sub-analyzers.

    This mechanism offers an advantage: switching to a different reward mechanism implies only switching from analyzer_reward_A to analyzer_reward_B.

    In any case such analyzer_reward_X would need to offer a well-defined interface.



  • I managed to implement a Particle Swarm Optimization algorithm to optimize two SMA parameters in the example strategy.

    The PSO algorithm is part of the opptunity python package at https://github.com/claesenm/optunity

    Essentially the steps are:

    1. define strategy as per usual
    2. define a function to accept parameters, run the strategy, and return a performance measure (in this case, net value of the portfolio)
    3. pass function in #2 to the optimizer and let it do its work
    4. take optimal parameters calculated in #3 and pass into the function in #2 to get result

    This method works well, although the opptunity library has some known limitations (e.g. can only work with float-based parameters.. thus having to convert to int in the strategy). Hopefully this is helpful for anyone trying to do the same thing.

    # example of optimizing SMA crossover strategy parameters using 
    # Particle Swarm Optimization in the opptunity python library
    # https://github.com/claesenm/optunity
    
    from datetime import datetime
    import backtrader as bt
    
    import optunity
    import optunity.metrics
    
    
    class SmaCross(bt.SignalStrategy):
        params = (
            ('sma1', 10),
            ('sma2', 30),
        )
        def __init__(self):
            SMA1 = bt.ind.SMA(period=int(self.params.sma1))
            SMA2 = bt.ind.SMA(period=int(self.params.sma2))
            crossover = bt.ind.CrossOver(SMA1, SMA2)
            self.signal_add(bt.SIGNAL_LONG, crossover)
    
    
    data0 = bt.feeds.YahooFinanceData(dataname='YHOO',
                                      fromdate=datetime(2011, 1, 1),
                                      todate=datetime(2012, 12, 31))
    
    def runstrat(sma1,sma2):
        
        cerebro = bt.Cerebro()
        cerebro.addstrategy(SmaCross, sma1=sma1, sma2=sma2)
    
        cerebro.adddata(data0)
        cerebro.run()
        return cerebro.broker.getvalue()
    
    opt = optunity.maximize(runstrat,  num_evals=100, sma1=[2, 55], sma2=[2, 55])
    
    optimal_pars, details, _ = opt
    print('Optimal Parameters:')
    print('sma1 = %.2f' % optimal_pars['sma1'])
    print('sma2 = %.2f' % optimal_pars['sma2'])
    
    cerebro = bt.Cerebro()
    cerebro.addstrategy(SmaCross, sma1=optimal_pars['sma1'], sma2=optimal_pars['sma2'])
    cerebro.adddata(data0)
    cerebro.run()
    cerebro.plot()


  • Many thanks for the code!
    It is quite short and easy to understand



  • I've tried pyevolve library for evolutionary optimization. This is first shot for the system shown above (2 params only, but lets be consistent), takes longer time than particle swarm optimization.

    # example of optimizing SMA crossover strategy parameters using 
    # evolutionary Optimization in the pyevolve python library
    # http://pyevolve.sourceforge.net/
    
    from datetime import datetime
    import backtrader as bt
    
    from pyevolve import G1DList
    from pyevolve import GSimpleGA
    
    class SmaCross(bt.SignalStrategy):
        params = (
            ('sma1', 10),
            ('sma2', 30),
        )
    
        def __init__(self):
            SMA1 = bt.ind.SMA(period=int(self.params.sma1))
            SMA2 = bt.ind.SMA(period=int(self.params.sma2))
            crossover = bt.ind.CrossOver(SMA1, SMA2)
            self.signal_add(bt.SIGNAL_LONG, crossover)
    
    data0 = bt.feeds.YahooFinanceData(dataname='YHOO',
                                      fromdate=datetime(2011, 1, 1),
                                      todate=datetime(2012, 12, 31))
    
    def runstrat(chromosome):
        
        cerebro = bt.Cerebro()
        cerebro.addstrategy(SmaCross, sma1=chromosome[0], sma2=chromosome[1])
    
        cerebro.adddata(data0)
        cerebro.run()
        return cerebro.broker.getvalue()
    
    genome = G1DList.G1DList(2)
    genome.setParams(rangemin=2, rangemax=55)
    genome.evaluator.set(runstrat)
    ga = GSimpleGA.GSimpleGA(genome)
    ga.setGenerations(5)
    ga.setMutationRate(0.2)
    ga.setCrossoverRate(1.0)
    ga.setPopulationSize(10)
    ga.evolve(freq_stats=1)
    print ga.bestIndividual()
    


  • I've put more efforts trying to apply optunity module. It maybe not a discussion related to bt, but it would be nice to hear from people used/using optunity. If you can point me discussion board for optunity, I would appreciate it. I've run number of their solvers with different number of evaluations and received interesting results.

    Strategy: 5 parameter strategy, 3 indicators. Total amount of parameter configurations 48 x 48 x 48 x 248 x 98 = 2,687,827,968 :). Recovery Factor (RF) was maximized.

    For optimization I've used the following optunity solvers: particle swarm, sobol, random search, cma-es, grid search with standard settings. I know that other trading software widely uses particle swarm and cma-es, so these solvers were my main hope.

    I've made 4 runs for each of the following number of evaluations: 100, 250, 500 and 750 (twice only).

    Results:

    particle swarm, sobol, random search: for the same number of evaluations each separte run gave different sets of parameters and different optimal RF. These RFs were quite far from maximum value.

    cma-es: same optimal parameters for 100, 250 and 500 evaluations resulted in zero RFs (meaning roughly negative returns of the strategy). And only 750 evaluations resulted in some positive values, again far from maximum value.

    grid search: same optimal parameters for all runs for the same number of evaluations, number of evaluations affects slightly, resulted in maximum RF from all study. Also took 2-2.5 less time compare to other solvers for the same number of evaluations.

    Best solver - grid search, which surprised me a lot.

    Inviting @d416 @Harel-Rozental



  • Hi,
    Well grid search should be the same as what backtrader does when you do optstrategy,
    so given the data-caching and other things it does behind the scenes it should be even faster for that.

    I don't see why grid-search should be faster than "smarter" algorithms, though obviously it is always optimal (in the constrained region).
    Weird.

    My intention is to try to make backtrader let me use optstrategy's speed with smart algorithms such as particle swarm or a variation of hill-climbing



  • @ab_trader said in Genetic Optimization:

    Best solver - grid search, which surprised me a lot.

    Excellent work. Grid Search is basically a run of all permutations of parameters so I'm also surprised it took less time. My only guesses for the reasons behind these results are:

    1. fetching the stats from cerebro in a wrapper function may not as efficient as the native optimizer would do it
    2. your Recovery Factor must be calculated at some point during the iterations... maybe this is slowing it down?
    3. In terms of grid search bearing the best RF, I find that algorithmic optimizers are best used if the goal is to find patters within data. Any type of reward that incorporates profit (net, gross, profit factor, etc.) are the best to use imo, since these optimizers tend to 'zero in' on the one optimal answer. With RF, there could be multiple optimal answers yielding slightly different results, so an optimizer may just end up picking a solution right down the middle. For these types of problems - i.e. the ones where a grid search would yield the best out of multiple possible results, Machine Learning algorithms would be the way to go. Example: http://machinelearningmastery.com/grid-search-hyperparameters-deep-learning-models-python-keras/

    My personal preference in optimizers is to get the top 10 iterations by measure of profit, then pick the best one that yielded a strategy-specific statistic. This ensures that I'm finding the patterns in the market as opposed to my strategy.

    Full disclosure: I'm not an expert by any means and I only know what I've read out there.. Also, Python is new to me, but hope it all helps people somehow nonetheless.

    If you can point me discussion board for optunity, I would appreciate it.

    According to the docs, this is the place to post optunity questions and comments:
    https://gitter.im/claesenm/optunity
    The creator also provides an email address:
    marc.claesen@esat.kuleuven.be



  • Something I just thought about - are you sure it's the same number of evaluations?
    If you look at a parameter such as period, going from 1 to 5,
    GrisSearch only has to run 5 times on it, whereas the other algorithms go over real numbers so they also try things such as 1.25 (which is just another way of saying 1 for this parameter).



  • @Harel-Rozental I've used same number of evaluations as an argument for optunity.maximize. Maybe internally it is transformed to the different amount of runs for evaluation function, I didn't check internal processing.



  • @d416 Thanks for the link!

    I've done optimization study on the Net profit, will post results later.

    I was also thinking that my number of evaluations (750 max) covers only tiny part of the all possible configurations, and it can be a reason that grid search is better, since it covers all the field even sparsely and has more chances to get to the maximum. Others simply stick in the localized area.



  • So in terms of stable outputs search methods (sobol, grid search, random search) won the race for Net profit optimization. grid search is least time consuming. particle swarm method might give more optimal results with larger number of evaluations and larger number of runs. Probably it will be more effective on smaller parameter spaces.

    Maybe the good approach is to make 2 step optimization:

    • identify some intermediate optimal parameters using search approaches
    • select smaller space near these parameters and run smarter approaches

Log in to reply
 

Looks like your connection to Backtrader Community was lost, please wait while we try to reconnect.