当前位置: 首页 > 后端技术 > Python

WonderTrader优化器及其应用

时间:2023-03-26 14:44:05 Python

参数优化器介绍在写一个CTA策略的参数优化器WtCtaOptimizer之前,本模块主要使用multiprocessing模块通过遍历参数,并发启动多个进程进行历史回测,然后汇总回生成回测报告测试结果。参数优化器主要支持以下几种类型的参数:固定参数,即遍历优化器时不需要改变的参数。add_fixed_pa??ram(name="barCnt",val=50)数值型可变参数,即通过设置thestepsizeandvalue范围用于遍历参数,大部分参数都是这种类型。参数选择的参数列表,一般用于遍历目标和循环等参数optimizer.add_listed_pa??ram(name="code",val_list=["CFFEX.IF.HOT","CFFEX.IC.HOT"])主要用途本文的目的是演示WtCtaOptimizer的用法。DualThrust简介首先,我们还是求助于WonderTrader惯用的DualThrust策略。DualThrust策略是一种突破性策略。它利用前N天的开盘高低收盘确定一个Range,然后用当前K线开盘价加上Range乘以一个系数得到一个上轨,减去Range乘以一个系数得到一个较低的轨道,当最新价格突破上轨时,做多,当最新价格突破下轨时,做空。在最初的DualThrust型号中,上下导轨是对称的。文中使用的DualThrust策略在实现时将上下轨的系数作为两个不同的参数。该策略的核心逻辑如下:defon_calculate(self,context:CtaContext):code=self.__code__#品种代码trdUnit=1#读取最后50个1分钟线(dataframe对象)theCode=codedf_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.closeshighs=df_bars.highslows=df_bars.lows#读取前几天到前一个交易日的数据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.最后在中计算出需要的数据finalslice'''#determine上下轨upper_bound=openpx+k1*max(hh-lc,hc-ll)lower_bound=openpx-k2*max(hh-lc,hc-ll)#读取当前位置curPos=context.stra_get_position(code)/trdUnitifcurPos==0:ifhighpx>=upper_bound:context.stra_enter_long(code,1*trdUnit,'enterlong')context.stra_log_text("Breakthrough%.2f>=%.2f,longpositionentry"%(highpx,upper_bound))returniflowpx<=lower_boundandnotself.__is_stk__:context.stra_enter_short(code,1*trdUnit,'entershort')context.stra_log_text("突破%.2f<=%.2f,空头入场"%(lowpx,lower_bound))returnelifcurPos>0:iflowpx<=lower_bound:context.stra_exit_long(code,1*trdUnit,'exitlong')context.stra_log_text("Breakthrough%.2f<=%.2f,longpositionexit"%(lowpx,lower_bound))returnelse:ifhighpx>=upper_boundandnotself.__is_stk__:context.stra_exit_short(code,1*trdUnit,'exitshort')context.stra_log_text("向上突破%.2f>=%.2f,空头出场"%(highpx,upper_bound))return初步回测策略准备好了,我们来做一个没有止盈止损的DualThrust性能的最优参数选择参数优化器调用代码如下:fromwtpy.appsimportWtCtaOptimizerfromStrategies.DualThrustimportStraDualThrustif__name__=="__main__":#新建一个优化器,设置最大worker进程数为8optimizer=WtCtaOptimizer(worker_num=4)#设置要使用的策略,只需要传入策略类型,并设置策略ID的前缀来区分各个策略实例optimizer.set_strategy(StraDualThrust,"Dt_IF_")#添加固定参数优化器.add_fixed_pa??ram(name="barCnt",val=50)optimizer.add_fixed_pa??ram(name="period",val="m5")optimizer.add_fixed_pa??ram(name="days",val=30)optimizer.add_fixed_pa??ram(name="code",val="CFFEX.IF.HOT")#在预设范围内添加参数,即只能在预设列表中选择参数,适用于code、cycles等参数#optimizer.add_listed_pa??ram(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('pressanykeytoexit\n')本例中工作进程数设置为4个,用户可以根据自己的需要自定义需要设置,一般建议设置的数量与CPU核心数相匹配。配置好优化器入口后,就可以开始回测了。优化器执行界面系统资源占用优化器批量回测完成后,我们可以得到一个总结报告。我们先根据收益风险比大于3进行初步筛选,最后我们选择交易次数最多的参数对,即k1和k2都等于0.4的组作为我们最基本的策略参数.首先使用WtBtAnalyst做一个性能分析。2019年股指期货在4000点左右,合约金额在120万左右。按照双倍杠杆,初始资金为120万。从性能上来看,这组参数还是很有潜力的。至于这个例子是否涉及过拟合,是否需要对样本外数据进行回测,这不是本文的讨论范围。从业绩分析来看,年化收益率达到52.6%,但最大回撤仅为5.36%。添加止损的基本参数组合已经确定,接下来我们需要添加止损逻辑。为了简化逻辑,我们采用固定价差止损的方式,在策略进入和退出逻辑前进行判断。止损的计算方式采用最新价与进场价的差价,当差价达到一定点位时,将进行止损。我们设置的止损点范围是0到10,每次跳0.2次。代码如下:defrunStopLossOptimizer():#新建一个优化器,设置最大worker进程数为8optimizer=WtCtaOptimizer(worker_num=4)#设置要使用的策略,只需要传入策略类型并同时设置策略ID前缀用于区分各个策略实例optimizer.set_strategy(StraDualThrust,"Dt_IF_SL_")#添加固定参数optimizer.add_fixed_pa??ram(name="barCnt",val=50)optimizer.add_fixed_pa??ram(name="period",val="m5")optimizer.add_fixed_pa??ram(name="days",val=30)optimizer.add_fixed_pa??ram(name="code",val="CFFEX.IF.HOT")optimizer.add_fixed_pa??ram(name="k1",val=0.4)optimizer.add_fixed_pa??ram(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。代码如下:defrunStopProfOptimizer():#新建一个优化器,设置最大worker进程数为8optimizer=WtCtaOptimizer(worker_num=4)#设置要使用的策略,只需要传入策略类型,同时设置策略ID前缀,用于区分各个策略实例optimizer.set_strategy(StraDualThrust,"Dt_IF_SP_")#添加固定参数optimizer.add_fixed_pa??ram(name="barCnt",val=50)optimizer.add_fixed_pa??ram(name="period",val="m5")optimizer.add_fixed_pa??ram(name="days",val=30)optimizer.add_fixed_pa??ram(name="code",val="CFFEX.IF.HOT")optimizer.add_fixed_pa??ram(name="k1",val=0.4)optimizer.add_fixed_pa??ram(name="k2",val=0.4)#添加可变参数,适合一般数值参数optimizer.add_mutable_param(name="spTicks",start_val=0,end_val=500,step_val=5,ndigits=1)#配置回测环境,主要是通过这种方式动态传递直接回测的一些参数,a优化器会动态构建回测引擎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之间。代码如下:defrunStopAllOptimizer():#新建一个优化器,设置最大worker进程数为8optimizer=WtCtaOptimizer(worker_num=4)#设置要使用的策略,只需要传入策略类型并同时设置策略ID前缀用于区分各个策略实例optimizer.set_strategy(StraDualThrust,"Dt_IF_ALL_")#添加固定参数optimizer.add_fixed_pa??ram(name="barCnt",val=50)optimizer.add_fixed_pa??ram(name="period",val="m5")optimizer.add_fixed_pa??ram(name="days",val=30)optimizer.add_fixed_pa??ram(name="code",val="CFFEX.IF.HOT")optimizer.add_fixed_pa??ram(name="k1",val=0.4)optimizer.add_fixed_pa??ram(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)#配置backtest环境,主要是通过这个传递直接回测的一些参数这样优化器会动态构造回测引擎optimizer.config_backtest_env(deps_dir='./common/',cfgfile='configbt.json',storage_type="csv",storage_path="./storage/")optimizer.confg_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")回测结果汇总表如下:来自上图出来了,完全的止盈止损逻辑还是可以提高盈风险比的,但是净利润还是会比没有止盈止损的时候低很多。让我们选择一组利润风险比最高的参数来看一下。战略绩效分析。最大回撤不低于无止盈止损的逻辑,而是直接损失收益率。最后,我们来看一下只有止盈逻辑的最优参数的性能分析。综上所述,我们可以看出,止损逻辑对策略性能没有正向提升,但止盈逻辑可以锁定大量本应回馈的利润。止损无效的原因可能是因为止损点的范围不合理,也可能是其他原因,这不在本文讨论范围内,有兴趣的读者可以自行研究。结语本文充分展示了使用WtCtaOptimizer优化DualThrust的进出场逻辑、止损逻辑、止盈逻辑、止盈止损匹配逻辑相关参数的过程。相信读者通过本文可以对WtCtaOptimizer的使用有一个大概的了解。最后申明一下,作者水平有限,文章中的一些方法可能并不合适。本文的目的不是为读者提供直接可用的策略。读者在阅读本文时一定要注意甄别,不要被作者误导。WonderTrader作为一个量化交易平台,旨在为更多用户提供更好的基础设施。也希望在体验WonderTrader后,如果读者用户觉得不错,可以代为推广,让作者更有动力分享更多好用的功能。最后看看WonderTraderWonderTrader的github地址:https://github.com/wondertrad...WonderTrader官网地址:https://wondertrader.github.iowtpy的github地址:https://github.com/wondertrad...Market有风险,投资需谨慎。以上声明仅为对历史事件的回顾,不代表对未来的看法,不作为任何投资建议。