参数优化器简介

之前针对CTA策略写了一个参数优化器WtCtaOptimizer,该模块次要通过遍历参数的形式,利用multiprocessing模块并发启动多个过程进行历史回测,而后汇总回测后果生成回测报表。
参数优化器次要反对以下几种参数类型:

  • 固定参数,即遍历的时候不须要更改的参数
optimizer.add_fixed_param(name="barCnt", val=50)
  • 数值类可变参数,即通过设置步长和数值范畴进行参数遍历,绝大多数参数都是这个类型
optimizer.add_mutable_param(name="k1", start_val=0.1, end_val=1.0, step_val=0.1, ndigits = 1)
  • 列表类可变参数,即给定预设的列表,进行参数抉择,个别用于遍历标的、周期等参数
optimizer.add_listed_param(name="code", val_list=["CFFEX.IF.HOT","CFFEX.IC.HOT"])

本文的次要目标就是演示WtCtaOptimizer的用法

DualThrust介绍

首先咱们还是祭出WonderTrader习用的DualThrust策略。

DualThrust策略是一个冲破策略,利用前N日的开高下收确定一个Range,而后利用以后K线的开盘价加上Range乘以一个系数失去一个上轨,减去Range乘以一个系数失去一个下轨,当最新价冲破上轨时做多,冲破下轨时做空。

DualThrust原模型中,高低轨是对称的,文本所用的DualThrust策略在实现时把高低轨的系数作为两个不同的参数,策略外围逻辑如下:

def on_calculate(self, context:CtaContext):    code = self.__code__    #种类代码    trdUnit = 1    #读取最近50条1分钟线(dataframe对象)    theCode = code    df_bars = context.stra_get_bars(theCode, self.__period__, self.__bar_cnt__, isMain = True)    #把策略参数读进来,作为长期变量,不便援用    days = self.__days__    k1 = self.__k1__    k2 = self.__k2__    #平仓价序列、最高价序列、最低价序列    closes = df_bars.closes    highs = df_bars.highs    lows = df_bars.lows    #读取days天之前到上一个交易日地位的数据    hh = np.amax(highs[-days:-1])    hc = np.amax(closes[-days:-1])    ll = np.amin(lows[-days:-1])    lc = np.amin(closes[-days:-1])    #读取明天的开盘价、最高价和最低价    # lastBar = df_bars.get_last_bar()    openpx = df_bars.opens[-1]    highpx = df_bars.highs[-1]    lowpx = df_bars.lows[-1]    '''    !!!!!这里是重点    1、首先依据最初一条K线的工夫,计算以后的日期    2、依据以后的日期,对日线进行切片,并截取所需条数    3、最初在最终切片内计算所需数据    '''    #确定上轨和下轨    upper_bound = openpx + k1* max(hh-lc,hc-ll)    lower_bound = openpx - k2* max(hh-lc,hc-ll)    #读取以后仓位    curPos = context.stra_get_position(code)/trdUnit    if curPos == 0:        if highpx >= upper_bound:            context.stra_enter_long(code, 1*trdUnit, 'enterlong')            context.stra_log_text("向上冲破%.2f>=%.2f,多仓进场" % (highpx, upper_bound))            return        if lowpx <= lower_bound and not self.__is_stk__:            context.stra_enter_short(code, 1*trdUnit, 'entershort')            context.stra_log_text("向下冲破%.2f<=%.2f,空仓进场" % (lowpx, lower_bound))            return    elif curPos > 0:        if lowpx <= lower_bound:            context.stra_exit_long(code, 1*trdUnit, 'exitlong')            context.stra_log_text("向下冲破%.2f<=%.2f,多仓出场" % (lowpx, lower_bound))            return    else:        if highpx >= upper_bound and not self.__is_stk__:            context.stra_exit_short(code, 1*trdUnit, 'exitshort')            context.stra_log_text("向上冲破%.2f>=%.2f,空仓出场" % (highpx, upper_bound))            return

初步回测

策略筹备好了,咱们先针对DualThrust不加止盈止损的绩效进行一个最优参数抉择。参数优化器的调用代码如下:

from wtpy.apps import WtCtaOptimizerfrom Strategies.DualThrust import StraDualThrustif __name__ == "__main__":    # 新建一个优化器,并设置最大工作过程数为8    optimizer = WtCtaOptimizer(worker_num=4)    # 设置要应用的策略,只须要传入策略类型即可,同时设置策略ID的前缀,用于辨别每个策略的实例    optimizer.set_strategy(StraDualThrust, "Dt_IF_")    # 增加固定参数    optimizer.add_fixed_param(name="barCnt", val=50)    optimizer.add_fixed_param(name="period", val="m5")    optimizer.add_fixed_param(name="days", val=30)    optimizer.add_fixed_param(name="code", val="CFFEX.IF.HOT")    # 增加预设范畴的参数,即参数只能在预设列表中抉择,实用于标的代码、周期等参数    # optimizer.add_listed_param(name="code", val_list=["CFFEX.IF.HOT","CFFEX.IC.HOT"])    # 增加可变参数,实用于个别数值类参数    optimizer.add_mutable_param(name="k1", start_val=0.1, end_val=1.0, step_val=0.1, ndigits = 1)    optimizer.add_mutable_param(name="k2", start_val=0.1, end_val=1.0, step_val=0.1, ndigits = 1)    # 配置回测环境,次要是将间接回测的一些参数通过这种形式动静传递,优化器中会在每个子过程动静结构回测引擎    optimizer.config_backtest_env(deps_dir='./common/', cfgfile='configbt.json', storage_type="csv", storage_path="./storage/")    optimizer.config_backtest_time(start_time=201909100930, end_time=202010121500)    # 启动优化器    optimizer.go(interval=0.2, out_marker_file="strategies.json")    kw = input('press any key to exit\n')

本例中设置工作过程的个数为4个,用户能够自行依据本人的需要设置,个别举荐设置的个数和CPU内核数匹配。
优化器入口配置好了,就能够启动回测了。
优化器执行界面

系统资源占用状况

优化器批量回测实现当前,咱们能够失去一个汇总报表

咱们先依照收益危险比大于3,进行初步筛选。

最终咱们抉择交易次数最多的一个参数对,即k1和k2都等于0.4这组,作为咱们最根底的策略参数。先利用WtBtAnalyst做一下绩效剖析,2019年股指期货大略在4000点左右,合约价值大略120万,依照一倍杠杆,设置初始资金为120万。

从绩效来看,这组参数还是很有后劲的。至于本例是否波及到过拟合、是否要须要进行样本外数据的回测,这不是本文探讨的领域。从绩效剖析上来看,年化收益率达到了52.6%,然而最大回撤只有5.36%

退出止损

基本参数组合曾经确定了,接下来咱们要退出止损逻辑。为了简化逻辑,咱们采纳固定价差止损的形式,并且在策略进出场逻辑之前进行判断。止损的计算形式采纳最新价和进场价的价差,当价差达到肯定点位,则进行止损。
咱们将止损点位区间设置为0到10,每次0.2一跳。代码如下:

def runStopLossOptimizer():    # 新建一个优化器,并设置最大工作过程数为8    optimizer = WtCtaOptimizer(worker_num=4)    # 设置要应用的策略,只须要传入策略类型即可,同时设置策略ID的前缀,用于辨别每个策略的实例    optimizer.set_strategy(StraDualThrust, "Dt_IF_SL_")    # 增加固定参数    optimizer.add_fixed_param(name="barCnt", val=50)    optimizer.add_fixed_param(name="period", val="m5")    optimizer.add_fixed_param(name="days", val=30)    optimizer.add_fixed_param(name="code", val="CFFEX.IF.HOT")    optimizer.add_fixed_param(name="k1", val=0.4)    optimizer.add_fixed_param(name="k2", val=0.4)    # 增加可变参数,实用于个别数值类参数    optimizer.add_mutable_param(name="slTicks", start_val=0, end_val=10, step_val=0.2, ndigits = 1)    # 配置回测环境,次要是将间接回测的一些参数通过这种形式动静传递,优化器中会在每个子过程动静结构回测引擎    optimizer.config_backtest_env(deps_dir='./common/', cfgfile='configbt.json', storage_type="csv", storage_path="./storage/")    optimizer.config_backtest_time(start_time=201909100930, end_time=202010121500)    # 启动优化器    optimizer.go(interval=0.2, out_marker_file="strategies.json",out_summary_file="total_summary.csv")

汇总的回测后果如下。通过简略的剖析,咱们不难发现,尽管设置止损当前,对进步收益危险比有很大的促成,最大的是-0.2点止损,收益危险比能够达到17倍以上。然而付出的代价就是总收益的降落,设置了止损点当前,最终净收益比未设置止损点的时候,少了约30万~40万,约为原来的1/3~1/2

退出止盈

上面咱们再来看一下止盈逻辑。本文为了简化逻辑,采纳固定点位止盈
为了锁定更多利润,咱们将止盈点的范畴设置为0~500,每次5.0一跳。代码如下:

def runStopProfOptimizer():    # 新建一个优化器,并设置最大工作过程数为8    optimizer = WtCtaOptimizer(worker_num=4)    # 设置要应用的策略,只须要传入策略类型即可,同时设置策略ID的前缀,用于辨别每个策略的实例    optimizer.set_strategy(StraDualThrust, "Dt_IF_SP_")    # 增加固定参数    optimizer.add_fixed_param(name="barCnt", val=50)    optimizer.add_fixed_param(name="period", val="m5")    optimizer.add_fixed_param(name="days", val=30)    optimizer.add_fixed_param(name="code", val="CFFEX.IF.HOT")    optimizer.add_fixed_param(name="k1", val=0.4)    optimizer.add_fixed_param(name="k2", val=0.4)    # 增加可变参数,实用于个别数值类参数    optimizer.add_mutable_param(name="spTicks", start_val=0, end_val=500, step_val=5, ndigits = 1)    # 配置回测环境,次要是将间接回测的一些参数通过这种形式动静传递,优化器中会在每个子过程动静结构回测引擎    optimizer.config_backtest_env(deps_dir='./common/', cfgfile='configbt.json', storage_type="csv", storage_path="./storage/")    optimizer.config_backtest_time(start_time=201909100930, end_time=202010121500)    # 启动优化器    optimizer.go(interval=0.2, out_marker_file="strategies.json",out_summary_file="total_summary_sp.csv")

咱们将汇总的后果中收益危险比大于4的截取进去,如下图:

由上图能够见,止盈逻辑对策略绩效的晋升还是比拟显著的,然而当止盈点位在150点到230之间,收益危险比基本上达到稳固,策略绩效晋升约10%以上。

残缺回测

理论应用中,止盈止损当然不可能分为两个相互独立的逻辑来应用,反而是配合应用的。所以咱们最初再将止盈止损的参数进行联结优化。
依据下面的回测后果,咱们将止盈点位的范畴管制在150到230之间,止损点位管制在-30到-10之间。代码如下:

def runStopAllOptimizer():    # 新建一个优化器,并设置最大工作过程数为8    optimizer = WtCtaOptimizer(worker_num=4)    # 设置要应用的策略,只须要传入策略类型即可,同时设置策略ID的前缀,用于辨别每个策略的实例    optimizer.set_strategy(StraDualThrust, "Dt_IF_ALL_")    # 增加固定参数    optimizer.add_fixed_param(name="barCnt", val=50)    optimizer.add_fixed_param(name="period", val="m5")    optimizer.add_fixed_param(name="days", val=30)    optimizer.add_fixed_param(name="code", val="CFFEX.IF.HOT")    optimizer.add_fixed_param(name="k1", val=0.4)    optimizer.add_fixed_param(name="k2", val=0.4)    # 增加可变参数,实用于个别数值类参数    optimizer.add_mutable_param(name="slTicks", start_val=-30, end_val=-10, step_val=1, ndigits = 1)    optimizer.add_mutable_param(name="spTicks", start_val=150, end_val=230, step_val=2, ndigits = 1)    # 配置回测环境,次要是将间接回测的一些参数通过这种形式动静传递,优化器中会在每个子过程动静结构回测引擎    optimizer.config_backtest_env(deps_dir='./common/', cfgfile='configbt.json', storage_type="csv", storage_path="./storage/")    optimizer.config_backtest_time(start_time=201909100930, end_time=202010121500)    # 启动优化器    optimizer.go(interval=0.2, out_marker_file="strategies.json",out_summary_file="total_summary_all.csv")

回测后果汇总表如下:

从上图能够看进去,止盈止损残缺的逻辑,对于进步收益危险比还是有晋升的,然而净利润还是会比无止盈止损的时候升高不少。
咱们再抉择收益危险比最高的一组参数,看一下策略的绩效剖析。

最大回撤并没有比无止盈止损的逻辑低,反而间接损失了收益率。
咱们最初再看一下只有止盈逻辑的最优参数的绩效剖析。

综合下面咱们能够看进去,止损逻辑并没有对策略绩效有比拟正向的改善,反而止盈逻辑能锁定不少本来要回吐的利润。止损有效的起因何在,可能是因为止损点位的范畴设置不合理,或者是因为别的起因,这个就不在本文的探讨范畴了,有趣味的读者能够自行钻研一下。

结束语

本文残缺的演示了一遍利用WtCtaOptimizerDualThrust的进出场逻辑、止损逻辑、止盈逻辑以及止盈止损搭配的逻辑的相干参数进行优化的过程。置信各位读者通过本文,可能对WtCtaOptimizer的用法有一个大略的理解。

最初申明一下,笔者的程度无限,文中的一些办法也不肯定失当,本文的目标也不是要给各位读者提供一个间接可用的策略。各位读者在浏览本文的时候,肯定要留神甄别,不要被笔者误导。

WonderTrader作为一个量化交易平台,旨在为更多的用户提供更好的基础设施。也心愿各位读者和用户在体验过WonderTrader当前,感觉不错的话,可能多多代为推广,这样笔者能力更有能源去分享更多的好用的性能。

最初再安利一下WonderTrader

WonderTradergithub地址:https://github.com/wondertrad...

WonderTrader官网地址:https://wondertrader.github.io

wtpygithub地址:https://github.com/wondertrad...


市场有危险,投资需谨慎。以上陈说仅作为对于历史事件的回顾,不代表对将来的观点,同时不作为任何投资倡议。