参数优化器简介
之前针对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")
回测后果汇总表如下:
从上图能够看进去,止盈止损残缺的逻辑,对于进步收益危险比还是有晋升的,然而净利润还是会比无止盈止损的时候升高不少。
咱们再抉择收益危险比最高的一组参数,看一下策略的绩效剖析。
最大回撤并没有比无止盈止损的逻辑低,反而间接损失了收益率。
咱们最初再看一下只有止盈逻辑的最优参数的绩效剖析。
综合下面咱们能够看进去,止损逻辑并没有对策略绩效有比拟正向的改善,反而止盈逻辑能锁定不少本来要回吐的利润。止损有效的起因何在,可能是因为止损点位的范畴设置不合理,或者是因为别的起因,这个就不在本文的探讨范畴了,有趣味的读者能够自行钻研一下。
结束语
本文残缺的演示了一遍利用WtCtaOptimizer对DualThrust
的进出场逻辑、止损逻辑、止盈逻辑以及止盈止损搭配的逻辑的相干参数进行优化的过程。置信各位读者通过本文,可能对WtCtaOptimizer的用法有一个大略的理解。
最初申明一下,笔者的程度无限,文中的一些办法也不肯定失当,本文的目标也不是要给各位读者提供一个间接可用的策略。各位读者在浏览本文的时候,肯定要留神甄别,不要被笔者误导。
WonderTrader作为一个量化交易平台,旨在为更多的用户提供更好的基础设施。也心愿各位读者和用户在体验过WonderTrader当前,感觉不错的话,可能多多代为推广,这样笔者能力更有能源去分享更多的好用的性能。
最初再安利一下WonderTrader
WonderTrader的github
地址:https://github.com/wondertrad...
WonderTrader官网地址:https://wondertrader.github.io
wtpy的github
地址:https://github.com/wondertrad...
市场有危险,投资需谨慎。以上陈说仅作为对于历史事件的回顾,不代表对将来的观点,同时不作为任何投资倡议。