VeighNa量化社区
你的开源社区量化交易平台
Member
avatar
加入于:
帖子: 187
声望: 55

海龟策略的信号来源于唐奇安通道突破。简单的说就是若突破上轨则做多,突破下轨则做空。我们可以对信号进行改良,如换成布林带通道,金肯特纳通道等等,并且增加过滤条件和离场条件。

但是呢?新的问题又来了:若用了新的指标,需要通过不断调试来得到“最优”参数,这样会耗费大量的时间。

那么,有没有办法在尽量少得时间内,尽可能得到全局最优解或者次优解呢?

答案就是遗传算法啦!

 
 
 

遗传算法原理


具体原理详见:
遗传算法原理简介

一文读懂遗传算法工作原理(附Python实现)

 

遗传算法要做的事情并不复杂:

  1. 随机生成一大推策略参数(称之为族群,族群内的个体对应某一组策略参数)
  2. 族群内个体间进行3类活动:个体间两两交叉互换;个体某个参数发生变异;个体繁殖(即直接复制参数)
  3. 形成子代
  4. 通过目标函数(如最大化夏普比率,最大化总盈亏等)对母代族群和子代族群进行评分
  5. 通过特点筛选标准(如NSGA-Ⅱ)从母代和子代中筛选个体,形成第二代族群。(类似进化论中的“自然选择”)
  6. 新的族群在特定的评分标准和筛选标准中不断迭代(即重复1-5步骤),得到最优解/次优解。

 
 
 

遗传算法代码示例


1.随机生成待优化的策略参数

def parameter_generate():
    '''
    根据设置的起始值,终止值和步进,随机生成待优化的策略参数
    '''
    parameter_list = []
    p1 = random.randrange(4,50,2)      #入场窗口
    p2 = random.randrange(4,50,2)      #出场窗口
    p3 = random.randrange(4,50,2)      #基于ATR窗口止损窗
    p4 = random.randrange(18,40,2)     #基于ATR的动态调仓 

    parameter_list.append(p1)
    parameter_list.append(p2)
    parameter_list.append(p3)
    parameter_list.append(p4)

    return parameter_list

 

  1. 设置目标优化函数(收益回撤比和夏普比率)
def object_func(strategy_avg):
    """
    本函数为优化目标函数,根据随机生成的策略参数,运行回测后自动返回2个结果指标:收益回撤比和夏普比率
    """
    # 创建回测引擎对象
    engine = BacktestingEngine()
    # 设置回测使用的数据                       
    engine.setBacktestingMode(engine.BAR_MODE)      # 设置引擎的回测模式为K线
    engine.setDatabase("VnTrader_Daily_Db", 'XBTHOUR')  # 设置使用的历史数据库
    engine.setStartDate('20170401')                 # 设置回测用的数据起始日期
    engine.setEndDate('20181230')                   # 设置回测用的数据起始日期

    # 配置回测引擎参数
    engine.setSlippage(0.5)                        
    engine.setRate(0.2/100)                     
    engine.setSize(10)                            
    engine.setPriceTick(0.5)                      
    engine.setCapital(1000000) 

    setting = {'entryWindow': strategy_avg[0],       #布林带窗口
               'exitWindow': strategy_avg[1],        #布林带通道阈值
               'atrWindow': strategy_avg[2],         #CCI窗口
               'artWindowUnit': strategy_avg[3],}    #ATR窗口               

    #加载策略          
    engine.initStrategy(TurtleTradingStrategy, setting)    
    # 运行回测,返回指定的结果指标   
    engine.runBacktesting()          # 运行回测
    #逐日回测   
    engine.calculateDailyResult()
    backresult = engine.calculateDailyStatistics()[1] 

    returnDrawdownRatio = round(backresult['returnDrawdownRatio'],2)  #收益回撤比
    sharpeRatio= round(backresult['sharpeRatio'],2)                   #夏普比率
    return returnDrawdownRatio , sharpeRatio

 

3.运行基于Deap库的遗传算法(具体步骤看代码中文注释)

#设置优化方向:最大化收益回撤比,最大化夏普比率
creator.create("FitnessMulti", base.Fitness, weights=(1.0, 1.0)) # 1.0 求最大值;-1.0 求最小值
creator.create("Individual", list, fitness=creator.FitnessMulti)

def optimize():
    """"""   
    toolbox = base.Toolbox()  #Toolbox是deap库内置的工具箱,里面包含遗传算法中所用到的各种函数

    # 初始化     
    toolbox.register("individual", tools.initIterate, creator.Individual,parameter_generate) # 注册个体:随机生成的策略参数parameter_generate()                                          
    toolbox.register("population", tools.initRepeat, list, toolbox.individual)               #注册种群:个体形成种群                                    
    toolbox.register("mate", tools.cxTwoPoint)                                               #注册交叉:两点交叉  
    toolbox.register("mutate", tools.mutUniformInt,low = 4,up = 40,indpb=0.6)                #注册变异:随机生成一定区间内的整数
    toolbox.register("evaluate", object_func)                                                #注册评估:优化目标函数object_func()    
    toolbox.register("select", tools.selNSGA2)                                               #注册选择:NSGA-II(带精英策略的非支配排序的遗传算法)


    #遗传算法参数设置
    MU = 40                                  #设置每一代选择的个体数
    LAMBDA = 160                             #设置每一代产生的子女数
    pop = toolbox.population(400)            #设置族群里面的个体数量
    CXPB, MUTPB, NGEN = 0.5, 0.35, 40        #分别为种群内部个体的交叉概率、变异概率、产生种群代数
    hof = tools.ParetoFront()                #解的集合:帕累托前沿(非占优最优集)

    #解的集合的描述统计信息
    #集合内平均值,标准差,最小值,最大值可以体现集合的收敛程度
    #收敛程度低可以增加算法的迭代次数
    stats = tools.Statistics(lambda ind: ind.fitness.values)
    np.set_printoptions(suppress=True)            #对numpy默认输出的科学计数法转换
    stats.register("mean", np.mean, axis=0)       #统计目标优化函数结果的平均值
    stats.register("std", np.std, axis=0)         #统计目标优化函数结果的标准差
    stats.register("min", np.min, axis=0)         #统计目标优化函数结果的最小值
    stats.register("max", np.max, axis=0)         #统计目标优化函数结果的最大值

    #运行算法
    algorithms.eaMuPlusLambda(pop, toolbox, MU, LAMBDA, CXPB, MUTPB, NGEN, stats,
                              halloffame=hof)     #esMuPlusLambda是一种基于(μ+λ)选择策略的多目标优化分段遗传算法

    return pop

 
 
 

遗传算法效果


夏普比率1.9,总收益率1958%,最大百分比回撤37%,收益回撤比达53。

enter image description here
其解集收敛程度如下:
enter image description here

在得到一个好的曲线后,还要检查一下这些参数是否符合市场逻辑,尽量去避免过拟合的情况。下面举个反例:

这里使用金肯特纳通道+基于固定百分比移动止损策略。不管从曲线的形态和收敛程度来看都是挺正常的

enter image description here
enter image description here
但是在这种优化后参数中我们观察到trailingPercent=18%,这意味着价格从最高点回落18个点才平仓离场。在正常情况,这会带来非常糟糕的盈亏比。
enter image description here

 
 
 

总结

遗传算法本质上是一种加快策略研究的技术,相对于暴力穷举,它可以大大节省电脑运算时间。我们可以使用它,但不能过度依赖它,因为有可能输出的仅仅是一些很巧合的参数。所以,针对这些参数,需要做更加细致的回测。

毕竟,在策略研究中,细心与耐心也是非常重要的。

Administrator
avatar
加入于:
帖子: 4500
声望: 320

遗传算法优化将会作为标准功能添加到2.0的CTA回测引擎里面

Member
加入于:
帖子: 158
声望: 71

很好呀,已经用起来了,比之前跑好几天的全遍历优化运算量减少不少。

Member
加入于:
帖子: 158
声望: 71

如果可以多线程就好了,我现在跑这个遗传策略只能单线程,

Member
加入于:
帖子: 158
声望: 71

这两天一直在看DEAP库,发现已经提供多线程支持。而且很简单,直接在运行算法前面加上下面一段就可以。
在1.92跑着,暂时没有上面问题。
.....
import multiprocessing
pool = multiprocessing.Pool(processes=multiprocessing.cpu_count())
toolbox.register("map", pool.map)

# 运行算法
algorithms.eaMuPlusLambda(pop, toolbox, MU, LAMBDA, CXPB, MUTPB, NGEN, stats,
                          halloffame=hof)  # esMuPlusLambda是一种基于(μ+λ)选择策略的多目标优化分段遗传算法
....

https://deap.readthedocs.io/en/master/tutorials/basic/part4.html

Member
avatar
加入于:
帖子: 187
声望: 55

deap库提供了scoop和multiprocessing库的支持。但是发现在jupter notebook上运行仍然是单进程(纯py文件正常),另外有时会无法输入最终结果pop。
多进程问题在修复中

Member
加入于:
帖子: 158
声望: 71

想突变还是按照赋值时候范围比较好,
做了个新的突变函数,这样就确保突变的数还在赋值区间中。

def mutArrayGroup(individual,parameterlist, indpb):
    size = len(individual)
    parameterlist  = parameterlist()
    for i in xrange(size):
        if random.random() < indpb:
            individual[i] = parameterlist[i]

    return individual,

 toolbox.register("mutate", mutArrayGroup, parameterlist = parameter_generate, indpb=0.6)
Member
avatar
加入于:
帖子: 141
声望: 57

我在用遗传算法策略优化buffersize时talib会出现inputs are all NaN的情况,暴力穷举却不会出现这种错误,怎么办?应该是buffersize取一定范围的值导致talib收的数据不够返回NAN,可是穷举不会出错,目前只能用穷举了

Member
avatar
加入于:
帖子: 141
声望: 57

description

Member
加入于:
帖子: 158
声望: 71

上弦之月 wrote:

我在用遗传算法策略优化buffersize时talib会出现inputs are all NaN的情况,暴力穷举却不会出现这种错误,怎么办?应该是buffersize取一定范围的值导致talib收的数据不够返回NAN,可是穷举不会出错,目前只能用穷举了

关掉多线程,会有具体错误信息。
还有一个方法就是强行赋值skip issue

    try:
        profitLossRatio = round(backresult['profitLossRatio'],3)                   #夏普比率                 #夏普比率
        sharpeRatio= round(backresult['sharpeRatio'],3)
    except:
        print("Error ")
        sharpeRatio = 0
        profitLossRatio = 0                      #收益回撤比

    return sharpeRatio,profitLossRatio
Member
avatar
加入于:
帖子: 141
声望: 57

我跑两组参数优化,每个参数步进20,共400组回测,怎么跑遗传算法优化比穷举慢的多,跑VNPY的多进程回测20分钟就跑完了

Member
avatar
加入于:
帖子: 187
声望: 55

注意遗传算法有迭代书NGEN=40。这意味着要跑40个轮回。
其应用场景是多维度的参数优化,因为暴力穷举的数量上指数上升的;而遗传算法在每次迭代过程中都筛选的良好的参数,这样会大大降低测试的数量

Member
avatar
加入于:
帖子: 141
声望: 57

加了五个参数,各步进20优化出现这个错误
description

Member
avatar
加入于:
帖子: 187
声望: 55

能否展示一下你parameter_generate()函数,以及遗传算法中MU, LAMBDA, CXPB, MUTPB, NGEN等参数

Member
avatar
加入于:
帖子: 141
声望: 57

KeKe wrote:

能否展示一下你parameter_generate()函数,以及遗传算法中MU, LAMBDA, CXPB, MUTPB, NGEN等参数
用了楼上的修改版,改回去可以正常跑了,多谢解答

Member
加入于:
帖子: 158
声望: 71

写了一个类,GeneticOptimizeStrategy,

  1. Parameterlist 字典; 简化了调用参数和定义对应随机范围问题。只要在Parameterlist 中定义策略参数名称和对应的随机范围就可以,其中两个参数的元祖是两个之间随机数,调用random.uniform(),三个参数元祖是开始结束和中间步进,调用的是random.randrange(), 如果是数组就是在数组中间随机选择。
  2. Symbollist 字典,维护回测品种和数据
  3. poptoExcel方法,输出一个Excel,包括参数和value;参数可以直接调用。同时把相同项合并。效果如下图

发现多线程时候有报错
cPickle.PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup builtin.instanceme
搜索一下,发现是python2.7多进程问题,pool.map没法绑定包在类里面方法。

把evaluate的方法放在类外面做成静态方法绑定,虽然解决了pickle,但是在多线程情况下,策略参数名字和值的对应经出出错。
就把参数赋值的方式也改了,从
[value1,value2,value3...]变成[{key1:value1},{key2,value2},{key2,value2}...],这样。可以满足交叉,突变要求。进化算法要改下,详情见下文。

Member
avatar
加入于:
帖子: 141
声望: 57

@张国平 你加的这个mutArrayGroup会提示mutate(ind) too many values to unpack

Member
加入于:
帖子: 158
声望: 71

上弦之月 wrote:

@张国平 你加的这个mutArrayGroup会提示mutate(ind) too many values to unpack

检查下这个注册是不是正确 toolbox.register("mutate", self.mutArrayGroup, parameterlist=self.parameter_generate,indpb=0.6)

Member
avatar
加入于:
帖子: 141
声望: 57

张国平 wrote:

上弦之月 wrote:

@张国平 你加的这个mutArrayGroup会提示mutate(ind) too many values to unpack

检查下这个注册是不是正确 toolbox.register("mutate", self.mutArrayGroup, parameterlist=self.parameter_generate,indpb=0.6)
这个值是正确的

Member
加入于:
帖子: 158
声望: 71

把evaluate的方法放在类外面做成静态方法绑定,虽然解决了pickle,但是在多线程情况下,策略参数名字和值的对应经出出错。
就把参数赋值的方式也改了,从
[value1,value2,value3...]变成[{key1:value1},{key2,value2},{key3,value3}...],这样。可以满足交叉,突变要求。进化算法要改下。

    def parameter_generate(self):
        '''
        根据设置的起始值,终止值和步进,随机生成待优化的策略参数
        '''
        parameter_list = []
        for key, value in self.parameterlist.items():
            if isinstance(value, tuple):
                if len(value) == 3:
                    parameter_list.append({key:random.randrange(value[0], value[1], value[2])})
                elif len(value) == 2:
                    parameter_list.append({key:random.uniform(value[0], value[1])})
            elif isinstance(value, list):
                parameter_list.append({key:random.choice(value)})
            else:
                parameter_list.append({key:value})
        return parameter_list

parameter_list是类似vnpy optimize的格式,不过有所增强。 strategy_avg返回变成了[{key1:value1},{key2,value2},{key3,value3}...],包含字典的list格式也可以满足交叉和突变方法。

在进化筛选方法中object_func,使用下面遍历把[{key1:value1},{key2,value2},{key3,value3}...]变回{key1,value1,key2,value2...},这样就可以进入回测

    setting = {}
    for item in range(len(strategy_avg)):
        setting.update(strategy_avg[item])

最后,因为进化筛选方法object_func放在类外面,但必须要把一些回测参数,比如品种,日期等的传入,这里有两种方式可以实现,一个是把传入individual list改为Tuple list,变成[(individual, parameterPackage)..]这样list,但是就要修改algorithms.eaMuPlusLambda,比较麻烦。
还有一个是增强individual, 加入这个回测参数集做为属性。但是多线程也有些要注意,不得不把parameterPackage做为静态属性放在类里面,不然回提示parameterPackage为空。还没有找到比较合适处理方法

creator.create("Individual", list, fitness=creator.FitnessMulti, parameterPackage=parameterPackage)

完整新代码如下

# encoding: UTF-8

"""
展示如何执行参数优化。
"""

from __future__ import division
from __future__ import print_function
from vnpy.trader.app.ctaStrategy.ctaBacktesting import BacktestingEngine, MINUTE_DB_NAME, OptimizationSetting
from vnpy.trader.app.ctaStrategy.strategy.strategyBollChannel import BollChannelStrategy
import random
import numpy as np
from deap import creator, base, tools, algorithms
import multiprocessing
import time, datetime
import pandas as pd


def object_func(strategy_avgTuple):
    """
    本函数为优化目标函数,根据随机生成的策略参数,运行回测后自动返回2个结果指标:收益回撤比和夏普比率
    """

    strategy_avg = strategy_avgTuple
    paraSet = strategy_avgTuple.parameterPackage
    symbol = paraSet["symbol"]
    strategy = paraSet["strategy"]


    # 创建回测引擎对象
    engine = BacktestingEngine()
    # 设置回测使用的数据
    engine.setBacktestingMode(engine.BAR_MODE)  # 设置引擎的回测模式为K线
    engine.setDatabase("VnTrader_1Min_Db", symbol["vtSymbol"])  # 设置使用的历史数据库
    engine.setStartDate(symbol["StartDate"])  # 设置回测用的数据起始日期
    engine.setEndDate(symbol["EndDate"])  # 设置回测用的数据起始日期

    # 配置回测引擎参数
    engine.setSlippage(symbol["Slippage"])  # 1跳
    engine.setRate(symbol["Rate"])  # 佣金大小
    engine.setSize(symbol["Size"])  # 合约大小
    engine.setPriceTick(symbol["Slippage"])  # 最小价格变动
    engine.setCapital(symbol["Capital"])

    setting = {}
    for item in range(len(strategy_avg)):
        setting.update(strategy_avg[item])

    engine.clearBacktestingResult()
    # 加载策略

    engine.initStrategy(strategy, setting)
    # 运行回测,返回指定的结果指标
    engine.runBacktesting()  # 运行回测
    # 逐日回测
    # engine.calculateDailyResult()
    backresult = engine.calculateBacktestingResult()

    try:
        capital = round(backresult['capital'], 3)  # 收益回撤比
        profitLossRatio = round(backresult['profitLossRatio'], 3)  # 夏普比率                 #夏普比率
        sharpeRatio = round(backresult['sharpeRatio'], 3)
    except Exception, e:
        print("Error: %s, %s" %(str(Exception),str(e)))
        sharpeRatio = 0
        profitLossRatio = 0  # 收益回撤比
        averageWinning = 0  # 夏普比率                 #夏普比率
        capital = 0
    return capital, sharpeRatio, profitLossRatio


class GeneticOptimizeStrategy(object):
    Strategy = BollChannelStrategy
    Symbollist ={
                    "vtSymbol": 'rb0000',
                    "StartDate": "20140601",
                    "EndDate": "20141101",
                    "Slippage": 1,
                    "Size": 10,
                    "Rate": 2 / 10000.0,
                    "Capital": 10000
                    }
    Parameterlist = {
                    'bollWindow': (10,50,1),       #布林带窗口
                    'bollDev': (2,10,1),        #布林带通道阈值
                    'slMultiplier':(3,6),
                    'barMins':[2,3,5,10,15,20],
    }
    parameterPackage = {
    "symbol":Symbollist,
    "strategy":Strategy
    }


    # ------------------------------------------------------------------------
    def __init__(self, Strategy, Symbollist, Parameterlist):
        self.strategy = Strategy
        self.symbol = Symbollist
        self.parameterlist = Parameterlist
        self.parameterPackage = {
            "strategy":self.strategy,
            "symbol":self.symbol
        }

    creator.create("FitnessMulti", base.Fitness, weights=(1.0, 1.0, 1.0))  # 1.0 求最大值;-1.0 求最小值
    creator.create("Individual", list, fitness=creator.FitnessMulti, parameterPackage=parameterPackage)


    # ------------------------------------------------------------------------
    def parameter_generate(self):
        '''
        根据设置的起始值,终止值和步进,随机生成待优化的策略参数
        '''
        parameter_list = []
        for key, value in self.parameterlist.items():
            if isinstance(value, tuple):
                if len(value) == 3:
                    parameter_list.append({key:random.randrange(value[0], value[1], value[2])})
                elif len(value) == 2:
                    parameter_list.append({key:random.uniform(value[0], value[1])})
            elif isinstance(value, list):
                parameter_list.append({key:random.choice(value)})
            else:
                parameter_list.append({key:value})
        return parameter_list


    def mutArrayGroup(self, individual, parameterlist, indpb):
        size = len(individual)
        paralist = parameterlist()
        for i in xrange(size):
            if random.random() < indpb:
                individual[i] = paralist[i]
        return individual,



    def optimize(self):
        # 设置优化方向:最大化收益回撤比,最大化夏普比率

        toolbox = base.Toolbox()  # Toolbox是deap库内置的工具箱,里面包含遗传算法中所用到的各种函数
        pool = multiprocessing.Pool(processes=(multiprocessing.cpu_count()-1))
        toolbox.register("map", pool.map)

        # 初始化
        toolbox.register("individual", tools.initIterate, creator.Individual,
                         self.parameter_generate)  # 注册个体:随机生成的策略参数parameter_generate()
        toolbox.register("population", tools.initRepeat, list,
                         toolbox.individual)  # 注册种群:个体形成种群
        toolbox.register("mate", tools.cxTwoPoint)  # 注册交叉:两点交叉
        toolbox.register("mutate", self.mutArrayGroup, parameterlist=self.parameter_generate,
                         indpb=0.6)  # 注册变异:随机生成一定区间内的整数
        toolbox.register("evaluate", object_func)  # 注册评估:优化目标函数object_func()
        toolbox.register("select", tools.selNSGA2)  # 注册选择:NSGA-II(带精英策略的非支配排序的遗传算法)

        # 遗传算法参数设置
        MU = 8  # 设置每一代选择的个体数
        LAMBDA = 5  # 设置每一代产生的子女数
        pop = toolbox.population(20)  # 设置族群里面的个体数量

        CXPB, MUTPB, NGEN = 0.5, 0.3, 10 # 分别为种群内部个体的交叉概率、变异概率、产生种群代数
        hof = tools.ParetoFront()  # 解的集合:帕累托前沿(非占优最优集)

        # 解的集合的描述统计信息
        # 集合内平均值,标准差,最小值,最大值可以体现集合的收敛程度
        # 收敛程度低可以增加算法的迭代次数
        stats = tools.Statistics(lambda ind: ind.fitness.values)
        np.set_printoptions(suppress=True)  # 对numpy默认输出的科学计数法转换
        stats.register("mean", np.mean, axis=0)  # 统计目标优化函数结果的平均值
        stats.register("std", np.std, axis=0)  # 统计目标优化函数结果的标准差
        stats.register("min", np.min, axis=0)  # 统计目标优化函数结果的最小值
        stats.register("max", np.max, axis=0)  # 统计目标优化函数结果的最大值
        # 运行算法
        algorithms.eaMuPlusLambda(pop, toolbox, MU, LAMBDA, CXPB, MUTPB, NGEN, stats,
                                  halloffame=hof, verbose=True)  # esMuPlusLambda是一种基于(μ+λ)选择策略的多目标优化分段遗传算法

        return pop

    def poptoExcel(self, pop, number = 1000, path = "C:/data/"):
        #按照输入统计数据队列和路径,输出excel,这里不提供新增模式,如果想,可以改
        #dft.to_csv(path,index=False,header=True, mode = 'a')
        path = path +  self.strategy.className + "_" + self.symbol[ "vtSymbol"] + str(datetime.date.today())+ ".xls"
        summayKey = ["StrategyParameter","TestValues"]
        best_ind = tools.selBest(pop, number)
        dft = pd.DataFrame(columns=summayKey)

        for i in range(0,len(best_ind)-1):
            if i == 0:
                # new = pd.DataFrame([{"StrategyParameter":self.complieString(best_ind[i])},{"TestValues":best_ind[i].fitness.values}], index=["0"])
                dft = dft.append([{"StrategyParameter":self.complieString(best_ind[i]),"TestValues":best_ind[i].fitness.values}], ignore_index=True)
            elif str(best_ind[i-1]) == (str(best_ind[i])):
                pass
            else:
                #new = pd.DataFrame({"StrategyParameter":self.complieString(best_ind[i]),"TestValues":best_ind[i].fitness.values}, index=["0"])
                dft = dft.append([{"StrategyParameter":self.complieString(best_ind[i]),"TestValues":best_ind[i].fitness.values}], ignore_index=True)

        dft.to_excel(path,index=False,header=True)
        print("回测统计结果输出到" + path)

    def complieString(self,individual):
        setting = {}
        for item in range(len(individual)):
            setting.update(individual[item])
        return str(setting)



if __name__ == "__main__":
    Strategy = BollChannelStrategy

    Symbollist ={
                    "vtSymbol": 'rb0000',
                    "StartDate": "20140601",
                    "EndDate": "20141101",
                    "Slippage": 1,
                    "Size": 10,
                    "Rate": 2 / 10000.0,
                    "Capital": 10000
                    }
    Parameterlist = {
                    'bollWindow': (10,50,1),       #布林带窗口
                    'bollDev': (2,10,1),        #布林带通道阈值
                    'slMultiplier':(3,6),
                    'barMins':[2,3,5,10,15,20],
    }
    parameterPackage = {
    "symbol":Symbollist,
    "parameterlist":Parameterlist,
    "strategy":Strategy
    }



    GE = GeneticOptimizeStrategy(Strategy,Symbollist,Parameterlist)
    GE.poptoExcel(GE.optimize())

    print("-- End of (successful) evolution --")
© 2015-2022 上海韦纳软件科技有限公司
备案服务号:沪ICP备18006526号

沪公网安备 31011502017034号

【用户协议】
【隐私政策】
【免责条款】