不久前看到一篇文章QMT使用技巧的文章——“震惊!策略回测参数从500多秒提升到1秒,竟然这么简单?”。当时进去看了下,大概是对单股的双均线策略的快线参数和慢线参数进行寻优,从2001年起至今对50组参数进行寻优,从使用纯 python 到使用 VBA 公式,从380秒优化到 1.3 秒。便想着动手看看 hikyuu 实现同样的参数寻优需要多久。
其实曾经也有人问过如何用 hikyuu 进行参数寻优,但觉得这种参数寻优本质是一种过拟合,一直不怎么感兴趣。所以友情提醒各位看官,这种简单的参数寻优本质是对历史数据的绝对过度拟合,请不要轻易使用寻优出来的结果,(凡是看到所谓的参数寻优,都请保持理性)!!!
这里使用经典双均线趋势策略(快线 > 慢线买入、反之卖出),测试执行机器为 i9-14900K, DD5-5600。50组参数,hikyuu执行时间:92毫秒,最佳参数 7, 51。
接下来进入正题,看看如何使用 Hikyuu 来完成这种参数寻优。(完整代码见文后附图)
一、构建参数组合
在 python 中构建参数组合是非常简单的,最经典的写法就是循环:
fast_n_range = range(5, 10, 1) slow_n_range = range(50, 60, 1) params = [] for fast_n in fast_n_range: for slow_n in slow_n_range: if slow_n > fast_n: params.append((fast_n, slow_n))
更加 pythonic 的写法:
from itertools import product params = [v for v in product(fast_n_range, slow_n_range)] # 构建参数两两组合 params = [(fast_n, slow_n) for fast_n, slow_n in params if fast_n < slow_n] # 过滤掉 slown <= fast_n 的参数组合
二、为每一对参数组合构建系统交易实例
这里直接使用默认 hub 中的经典双均线策略,由于后面使用的是茅台进行测试,请注意创建 TM (交易账户管理实例)时,保证有充足的资金,这里直接设置账户初始资金为 100000。
为了后续观察结果方便,更改每一个系统实例的名称,在其原有名称后加上实际的参数值,如:SYS_3_5。
sys_list = [] for x, y in params: # 创建趋势双均线系统实例,各自测试账户初始资金为 1000000,无止损/止盈/资金控制/交易成本 my_sys = get_part('default.sys.趋势双均线', fast_n=x, slow_n=y, tm=crtTM(init_cash=1000000), mm=MM_Nothing()) # 重新命名系统实例名称,如:SYS_3_5 my_sys.name = f'{my_sys.name}_{x}_{y}' sys_list.append(my_sys)
三、执行比较每个交易系统绩效,选出最优系统
为了方便,这里创建了一个函数,函数的主要功能就是循环执行指定每一个系统,并统计其绩效,最终返回绩效最高的系统和其绩效值。
def find_optimal_param(sys_list, stk, query, key=None): """ 该函数用于寻找系统列表中具有最高指定性能指标的系统。 参数: sys_list (list): 系统对象的列表。 stk (object): 用于系统运行的股票数据对象。 query (object): 查询对象,用于系统运行。 key (str, optional): 性能指标的键,默认为'帐户平均年收益率%'。 返回: tuple: 包含最高性能指标值和对应系统的元组。 异常: Exception: 如果提供的性能指标键无效,则抛出异常。 """ if key is None: key = '帐户平均年收益率%' if not Performance.exist(key): raise Exception(f"Invalid key: {key}") max_val = -10000 max_sys = None for my_sys in sys_list: my_sys.run(stk, query) per = Performance() per.statistics(my_sys.tm, lastdate) val = per[key] if val > max_val: max_val = val max_sys = my_sys return max_val, max_sys
四、执行结果
指定待测试的股票,测试时间范围,执行测试:
stk = sm[stk_code] query = Query(Datetime(20010101)) max_val, max_sys = find_optimal_param(sys_list, stk, query, key='当前总资产') print(max_val) print(max_sys.name) print(len(sys_list)) max_sys.run(stk, query) max_sys.performance()
执行耗时:
顺便测试了 fast_n [5, 80], slow_n [50, 200] 共 10785 组参数组合,耗时 24.5 秒。
完整代码:
欢迎加入星球:
关注公众号: