量化交易回测系列二:多因子Alpha策略回测
本文解释多因子模型与 alpha 策略的基本思路、特征,并与套利策略进行对比与讨论适用性。
Source: https://dolphindb.cn/blogs/13
What this page covers
- 多因子 Alpha 策略与多因子模型的背景与概念梳理。
- 因子生成:输入数据结构、信号定义与相关函数说明。
- 回测框架分解:组合权重、仓位与盈亏、业绩统计。
- 按历史周期计算组合,并行化与分区数据库组织方式。
- 按 tranche/因子/日期生成仓位与盈亏明细的计算方法。
- 运行实例:美股数据回测、绘图与性能描述。
- 讨论与未覆盖问题:因子间权重配置与新因子增量 alpha。
技能认证特训营第二期正式开启(限时报名)
页面顶部提供活动通知与报名链接入口。
- 提供“技能认证特训营第二期”的报名链接。
- 该入口位于页面顶部通知区域。
量化交易回测系列二:多因子Alpha策略回测
本节给出文章标题,并标注作者与发布日期。
- 文章标题为“量化交易回测系列二:多因子Alpha策略回测”。
- 署名作者为 Junxi。
- 发布日期为 2021-05-14。
多因子 Alpha 策略与多因子模型背景
本节解释多因子模型与 alpha 策略的思路与特征,并讨论与套利策略的对比及适用性。
- 多因子模型思路是寻找与回报率最相关的指标来构建组合。
- 组合构建方式包含做多正相关股票与做空负相关股票。
- 单因子权重常实现多空均衡与市场中性(beta 为 0)。
- 该类策略被描述为不暴露市场风险头寸的 alpha 策略。
- 文本提到与套利策略对比:套利 sharpe ratio 通常更高但 scale 不好。
1. 生成因子
本节说明输入数据结构,并给出因子生成函数、因子定义与相关 DolphinDB 函数说明。
- genSignals 的输入表 inData 包含 sym、date、close、RET、MV、VOL 字段。
- genSignals 过滤条件包括:weekday(date) between 1:5。
- genSignals 过滤条件包括:close>5、VOL>0、MV>100000,并按 sym、date 排序。
- 规模因子 signal_size 定义为 -sqrt(MV)。
- 波动率因子 signal_vol 定义为 -mstd(RET,21)*sqrt(252)。
- 动量因子 signal_mom 使用过去 12 个月并去除最近 1 个月的构造方式。
- beta 因子 signal_beta 用过去三个月数据计算 mbeta(RET, mRet, 63)。
- mRet 作为市场回报代理:按 date 分组对 RET 做 prevMV 加权平均。
- genSignals 输出字段包括 sym、date、close、ret、以及四个 signal 字段。
- genSignals 输出仅保留 date>=1991.01.01 的数据。
2. 回测框架
本节给出多因子 Alpha 回测框架的总体分解。
- 框架包含“生成每个周期的权重(tranche)”。
- 框架包含“根据持有时间生成每日仓位与盈亏”。
- 框架包含“统计分析各策略及总体业绩”。
2.1 计算历史周期的投资仓位
本节介绍如何按周期(一天)计算投资仓位,并扩展到历史每一天的并行计算。
- 讨论按“一个周期(一天)”计算投资仓位的方法。
- 讨论将计算扩展到历史每一天。
- 提到通过并行计算方式处理历史周期。
2.1.1 计算一天的股票投资组合
本节描述权重约束、因子矩阵构造、权重修剪逻辑,并给出 formPeriodPort 的输入输出与实现要点。
- 单因子约束:一天内该因子所有股票权重之和为 0。
- 跨因子约束:不同因子之间相互正交。
- 因子矩阵 sigMat:列为因子、行为股票,并添加全为 1 的单位因子列。
- 对信号进行去均值处理(x - avg(x))。
- 通过去除权重较小的股票来控制实际交易股票数量。
- formPeriodPort 输入包含 signals、signalNames、stockPercentile。
- formPeriodPort 输出字段为 tranche、sym、signalIdx、exposure。
- 每个因子多空各分配一美元,并修剪小权重。
2.1.2 计算过去每天的股票投资组合
本节说明使用分区内存数据库与 map-reduce,将 formPeriodPort 应用于每个交易日并写入分区表。
- 回测数据量很大,因此使用内存分区数据库与并行计算。
- 将 genSignals 输出保存到分区表 partSignals,分区粒度为“一天”。
- 创建分区表 ports 保存组合结果,分区粒度为“一年”。
- 使用 map-reduce:对每一天调用 formPeriodPort 并合并写入 ports。
- 提供分区数据库教程链接作为参考。
2.2 计算仓位和盈亏
本节定义 calcStockPnL,用于生成按 tranche/因子/日期的仓位与盈亏明细,并通过 map-reduce 写入分区表。
- calcStockPnL 的目标是生成每只股票在每个 tranche、每个因子上的每日仓位与盈亏。
- 计算结果保存到分区表 pnls。
- calcStockPnL 输入 ports 字段为 tranche、sym、signalIdx、exposure。
- calcStockPnL 输入 dailyRtn 字段为 date、sym、ret。
- holdingDays 表示股票持有的天数。
- calcStockPnL 输出字段为 date、sym、signalIdx、tranche、age、ret、exposure、pnl。
3. 运行实例
本节以美国股市为例运行回测,展示执行流程、绘图输出,并描述计算规模与性能。
- 运行示例以美国股市为例进行回测。
- 输入日数据表 USPrices 字段为 sym、date、close、RET、MV、VOL。
- 示例参数 holdingDays 设为 5。
- 示例参数 stockPercentile 设为 20。
- 示例因子集合为 signal_mom、signal_vol、signal_beta、signal_size。
- 示例流程包含:signals=genSignals(USPrices)。
- 示例流程包含:ports=formPortfolio(signals, signalNames, stockPercentile)。
- 示例流程包含:pos=calcStockPnL(ports, dailyRtn, holdingDays)。
- 对 pnl 聚合后绘制累计盈亏图。
- 图表说明涉及四因子累计盈亏(Cumulative PnL)走势。
- 图表说明涉及动量因子在不同持有天数下的累计盈亏走势。
- DolphinDB 被描述为通用的分布式时序数据库,内置多范式编程语言。
- 实现规模描述为:3 个自定义函数与 50 余行代码。
- 盈亏明细表记录数描述为 1 亿余条。
- 性能描述包含“单机(4 核)执行耗时仅 50 秒”的表述。
4. 讨论
本节指出框架当前覆盖范围与未解决问题,并预告后续文章将讨论的主题。
- 当前框架仅解决单个因子内的股票配置问题。
- 尚需解决因子间权重配置,以平衡回报与风险。
- 尚需判断新因子是否带来额外 alpha。
- 预告下一篇将讨论因子权重配置与新因子增量 alpha 的问题。
Facts Index
| Entity | Attribute | Value | Confidence |
|---|---|---|---|
| 技能认证特训营第二期 | 报名链接 | https://www.qingsuyun.com/h5/e/217471/5/ | high |
| 文章 | 发布日期 | 2021-05-14 | high |
| 文章作者 | 署名 | Junxi | high |
| 多因子模型 | 基本思路 | 找到与回报率最相关的指标并据此构建投资组合(做多正相关股票、做空负相关股票) | medium |
| 单因子个股权重(多因子模型) | 特征 | 一般实现多空均衡(市场中性),不暴露市场风险头寸(beta 为 0,因此称为 alpha 策略),能实现绝对收益 | medium |
| 多个因子 | 关系/作用 | 多个因子之间相互正交,便于策略配置,实现回报和风险的最优控制 | low |
| 多因子 alpha 策略 vs 套利策略 | 对比 | 套利策略通常 sharpe ratio 更高但 scale 不好;多因子 alpha 策略有很好的 scale,可配置大量资金 | low |
| 多因子 Alpha 策略 | 应用场景 | 在对冲基金中的使用非常普遍 | low |
| 输入数据表 inData(genSignals) | 字段 | 包含 6 个字段:sym(股票代码), date(日期), close(收盘价), RET(日回报), MV(市值), VOL(交易量) | high |
| genSignals(inData) | 数据过滤条件 | weekday(date) between 1:5, close>5, VOL>0, MV>100000(并按 sym、date 排序) | high |
| 规模因子 signal_size | 定义 | MV 的平方根的相反数(-sqrt(MV)) | high |
| 波动率因子 signal_vol | 定义 | 过去一个月股价波动率的相反数(-mstd(RET, 21)*sqrt(252)) | high |
| 动量因子 signal_mom | 定义 | 过去 12 个月(去除最近 1 个月)的动量因子(move(cumretIndex,21)/move(cumretIndex,252)-1) | high |
| beta 因子 signal_beta | 定义 | 利用过去三个月的数据计算个股跟市场的 beta(mbeta(RET, mRet, 63)) | high |
| mRet(市场回报代理) | 计算方式 | 按 date 分组,对 RET 使用 prevMV 加权平均(wavg(RET, prevMV)) | high |
| genSignals 输出 | 输出字段 | sym, date, close, ret(由 RET 重命名), signal_size, signal_beta, signal_vol, signal_mom | high |
| genSignals 输出数据 | 起始日期过滤 | date>=1991.01.01 | high |
| DolphinDB 函数 | _abs | 取绝对值 | high |
| DolphinDB 函数 | _prev | 把向量中的所有元素向右移动一个位置 | high |
| DolphinDB 函数 | _cumprod | 计算累计乘积 | high |
| DolphinDB 函数 | _sqrt | 计算平方根 | high |
| DolphinDB 函数 | _mstd(X,k) | 计算移动标准差 | high |
| DolphinDB 函数 | _wavg(X,k) | 计算加权平均数 | high |
| DolphinDB 函数 | _move(X,k) | k>0 右移 k 位;k<0 左移 k 位 | high |
| DolphinDB 函数 | _mbeta(X,Y,k) | 计算普通最小二乘回归的系数估计 | high |
| 多因子 Alpha 策略回测框架 | 组成部分 | 包含 3 个部分:生成每个周期的权重(tranche)、根据持有时间生成每日仓位与盈亏、统计分析各策略及总体业绩 | high |
| 一天组合权重(单因子约束) | 约束条件 | 一个因子中所有股票的权重和为 0(多空均衡) | high |
| 一天组合权重(跨因子约束) | 约束条件 | 不同因子之间相互正交:第 i 个因子的权重 wi 与第 j 个因子的值 sj 的内积为 0(i<>j) | high |
| 因子矩阵 sigMat | 构造说明 | 矩阵每列为一个因子、每行为一只股票,并添加单位因子列(全为 1);并对信号做去均值(x - avg(x)) | high |
| 实际交易股票数量控制 | 处理方法 | 去除权重较小的股票(大部分权重很小可忽略),通过嵌套函数 f 调整单因子股票权重 | medium |
| formPeriodPort 函数 | 输入参数 | signals(8 字段:股票代码、日期、收盘价格、回报率和 4 个因子)、signalNames(因子名称向量)、stockPercentile(控制股票数量) | high |
| formPeriodPort 输出 | 输出字段 | 数据表包含 4 个字段:tranche, sym, signalIdx, exposure | high |
| formPeriodPort 逻辑 | exposure 分配/修剪 | 对每个因子多空各分配一美元(allocate two dollars on each signal, one for long and one for short);并修剪小权重(trim small weights) | high |
| DolphinDB 函数 | _size | 返回向量中元素的个数 | high |
| DolphinDB 函数 | _first | 返回第一个元素 | high |
| DolphinDB 函数 | _matrix | 构建矩阵 | high |
| DolphinDB 函数 | _transpose | 矩阵转置 | high |
| DolphinDB 函数 | _dot | 矩阵或向量内积 | high |
| DolphinDB 函数 | _inv | 矩阵求逆 | high |
| DolphinDB 函数 | _iif(condition, trueResult, falseResult) | 满足条件返回 trueResult,否则返回 falseResult(逐元素 if...else) | high |
| DolphinDB 函数 | _loop(func,args) | 高价模板函数:对 args 每个元素应用 func 并汇总为元组 | high |
| DolphinDB 函数 | _unionAll | 合并多个表 | high |
| 回测计算环境 | 原因/做法 | 回测数据量非常庞大,将数据放到内存分区数据库并使用并行计算 | medium |
| 参考链接 | 分区数据库教程 | https://zhuanlan.zhihu.com/p/46299595 | high |
| partSignals 分区表 | 分区粒度 | 将 genSignals 生成的数据保存到分区表 partSignals;一个分区表示一天 | high |
| ports 分区表 | 分区粒度 | 创建分区表 ports 保存股票投资组合;一个分区表示一年 | high |
| formPortfolio | 并行计算方式 | 使用 map-reduce,将 formPeriodPort 应用于每一天,并将结果合并到分区表 ports | high |
| DolphinDB 函数 | _sort | 把向量中的元素排序 | high |
| DolphinDB 函数 | _database(directory,[partitionType],[partitionScheme],[locations]) | 创建数据库;directory 为空时创建内存数据库 | high |
| DolphinDB 函数 | _createPartitionedTable(dbHandle, table,[tableName], partitionColumns) | 在数据库中创建分区表 | high |
| DolphinDB 函数 | _datatimeParse(X, format) | 把字符串转换成 DolphinDB 时间类型数据 | medium |
| DolphinDB 函数 | _type | 返回数据类型的 ID | high |
| DolphinDB 函数 | _mr(ds, mapFunc,[reduceFunc],[finalFunc],[parallel=true]) | map-reduce 函数 | high |
| calcStockPnL 任务目标 | 输出内容 | 根据仓位与持有时间,生成每只股票在每个 tranche、每个因子上每一天的仓位和盈亏,并保存到分区表 pnls | high |
| calcStockPnL 输入 | ports 字段 | tranche, sym, signalIdx, exposure | high |
| calcStockPnL 输入 | dailyRtn 字段 | date, sym, ret | high |
| calcStockPnL 输入 | holdingDays 含义 | 股票持有的天数 | high |
| calcStockPnL 输出 | 输出字段 | 8 个字段:date, sym, signalIdx, tranche, age, ret, exposure, pnl | high |
| DolphinDB 函数 | _dict(key,value) | 创建字典 | high |
| DolphinDB 函数 | _cj(leftTable,rightTable) | 交叉连接两个表 | high |
| DolphinDB 函数 | _isValid | 检查元素是否为 NULL;非 NULL 返回 1,NULL 返回 0 | high |
| DolphinDB 函数 | _ej(leftTable,rightTable, matchingCols,[rightMatchingCols]) | 等值连接两个表 | high |
| 运行实例市场 | 市场范围 | 以美国股市为例运行多因子 Alpha 策略回测 | high |
| 输入日数据表 USPrices | 字段 | 6 个字段:sym, date, close, RET, MV, VOL | high |
| 运行示例参数 | holdingDays | 5 | high |
| 运行示例参数 | stockPercentile | 20 | high |
| 运行示例参数 | signalNames | `signal_mom`signal_vol`signal_beta`signal_size | high |
| 运行示例流程 | 步骤 | signals=genSignals(USPrices);ports=formPortfolio(signals, signalNames, stockPercentile);dailyRtn=select sym,date,ret from signals;pos=calcStockPnL(ports, dailyRtn, holdingDays);并对 pnl 聚合后绘制累计盈亏图 | high |
| 图表(四因子累计盈亏) | 展示内容(AI 说明) | 展示动量、波动率、贝塔、市值四因子从 1992 至 2017 的累计盈亏(Cumulative PnL)走势;基于 DolphinDB 对 25 年美股历史数据回测生成 | low |
| 图表(动量因子不同持有天数) | 展示内容(AI 说明) | 展示动量因子在五个不同持有天数(Age C1 至 C5)下的累计盈亏走势,用于分析信号随持仓时间增加的衰减情况;结果基于 DolphinDB 对上亿条盈亏记录的计算 | low |
| DolphinDB | 产品定位 | 通用的分布式时序数据库,内置高效的多范式编程语言,用于量化交易开发效率高 | medium |
| 多因子回测框架实现规模 | 代码量 | 仅用 3 个自定义函数,50 余行代码 | medium |
| 回测结果明细表(盈亏明细) | 记录数 | 包含 1 亿余条记录 | medium |
| 单机回测性能 | 硬件与耗时 | 单机(4 核)执行耗时仅 50 秒(对美股 25 年市值较高股票按日回测) | medium |
| 当前回测框架覆盖范围 | 未解决问题 | 仅解决单个因子中股票配置;仍需解决:因子间权重配置以平衡回报与风险;新因子是否带来额外 alpha(能否由已有因子表示) | high |
| 后续内容 | 预告 | 下一篇文章将介绍如何使用 DolphinDB 回答因子权重配置与新因子增量 alpha 的问题 | high |