为什么机器学习应用交易那么难(上)
全网TOP量化自媒体
公众号决定从2020年7月开始,每周一将推出一期有关全球对冲基金、量化投研、金融机器学习、机构招聘等方面的周刊。为大家带来最新、最前沿的投研、资讯内容,希望各位读者能够喜欢。
欢迎大家多提意见,我们完善到最优。
1
前言
今天这篇文章来自一家量化交易公司的某位研究员。他们试图通过大规模的机器学习技术来发现新颖的中频交易策略。
今天这位研究员来为大家分享一些他在工作中遇到的问题,仅供大家参考。
在这里,我们列举一些金融数据方面的挑战,以及为什么用机器学习建模会如此困难。
1、低信噪比
- 标签的噪音。
- 特征和度量是有噪声的变量。
2、特征向量非独立性
- 许多机器学习算法要求每个样本(特征向量/标签)独立于其他样本。
- 许多特征利用了窗口,在当前样本和之前样本之间创建重叠,共享同一回测周期的部分内容,这会对训练产生毁灭性的影响,导致模型偏差和过拟合。
3、标准损失函数不适合交易目标
- 我们对损失(False Positives)的厌恶程度远高于机会成本(False Negative),而机器学习模型试图去平衡精确度和召回率。
- 许多监督机器学习算法需要调整到一个合适的交易目标。
4、机会的稀疏性(对于某些策略)
- 含义:用于监督学习的非平衡数据集。
- 一个交易机会通常是一个“异常值”,一个在数据中不那么频繁的事件。大多数机器学习算法都是面向平衡数据集的。
5、非平稳性
- 价格是非平稳的,收益是无记忆的,需要在两者之间寻找平衡。
- 时间窗口不是固定的。
- 规则变化意味着基本交易模式的转变,即训练模式的复杂性。
6、数据缺乏
- 根据数据的频率或所需要的模型,金融数据往往不如其他领域的数据集丰富。
2
例子
假设我们想用机器学习来创建一个只做多的模型,来预测5天的收益率否大于某个最小收益率(比如50bps)。
1、创建标签,识别交易机会
我们将标记:
5天收益率>= 50bps with 1 和 < 50bps with 0
2、为模型创建特征
请注意,我们并不主张使用技术指标,下面的特征只是为了说明,并不是有意选择的。
3、训练模型
4、评估
5、完整代码
bars = getOHLC ("SPY")
close = bars["Adj Close"].values.flatten()
# 创建特征
df = bars.copy()
df["rsi"] = talib.RSI(close, timeperiod=14)
df["roc5"] = talib.ROC(close, timeperiod=5)
...
# 创建 { 0, 1 } 标签, where 1 means 5 day return >= 50bps
df["label"] = (df["roc5"].shift(-5) >= 0.50) * 1.0
# 特征的columns
features = ["rsi", "roc1", "roc5", "roc10", "roc20", "oc", "hl"]
# 数据集分割
icut = int(df.shape[0] * 0.70)
training = df.iloc[:icut].dropna()
testing = df.iloc[icut:].dropna()
# 训练模型&特征
clf = RandomForestClassifier(n_estimators=500, random_state=1, n_jobs=-1)
model = clf.fit (training[features], training.label)
#分别用模型对训练集和测试集的标签进行预测
pred_train = model.predict(training[features])
pred_test = model.predict(testing[features])
现在让我们看一下用于通过我们训练的模型进行训练和测试的混淆矩阵。对于交易,我们希望最大化TP(true-positive,盈利的交易)和最小化FP(false positives,亏损的交易):
在交易方面,我们不太关心TN(true negative)和FN(false negative)。false negative意味着错过了机会,但是没有损失。
现在,让我们根据训练数据和测试数据来评估模型的混淆矩阵。我们希望样本外的测试数据能够提供类似于训练的准确性,并且TP与FP的比值较高。
confusion_matrix(training.label, pred_train)
confusion_matrix(testing.label, pred_test)
结果表明,我们的训练周期有一个完美的契合(FN=0和FP=0)。这是一个很明显的过拟迹象:
而且在样本外测试中,损失的精度很差:
3
讨论
上面的例子说明了我们将在后续文章中讨论的一些问题:
1、标签有噪声
- 们已经指定+1标记的收益率>=50bps,但是其中一些收益率可能不能代表潜在的变动,而只围绕真实价格噪音的表现。例如,一段时期内的真实价格收益率可能为0,但方差为50个基点或更多。
- 们已经指定0标记的收益率< 50bps签,然而,在某些情况下,潜在的价格过程可能在该期间产生>= 50bps,但是由于大约50bps+平均值的波动,样本收益率降低到50bps以下。
- 因此,我们在某些情况下将模型映射到噪声中,并偏离模型。
2、特征是嘈杂的
- 特别是open-close和high-low特征,将受到波动性。
3、样本不是独立的
我们的特征集中的每一行都不是独立于相邻的行。最长的特征有一个20bar的lookback窗口。因此,每个特征行将与其他40个特征重叠(20个在过去+20个在未来)。许多机器学习算法由于非独立性而利用了信息泄露模型,在训练中产生了一个过拟合模型。
4、错误的损失目标
我们倾向于优化TP和FP(精度)之间的平衡,而不是平衡精度和召回率。
在后续的文章中,我们会更深入地讨论这些问题,并提出一些可以对算法、数据集等改进的方案。
- JavaMail开发示例,学习要看对资料
- 厚土Go学习笔记 | 34. 一个简单的 web 服务器实现
- sqlplus / as sysdba无法登录的奇怪报错 (r8笔记第36天)
- JSP与EL表达式重点学习笔记(1)
- R语言读CSV、txt文件方式以及read.table read.csv 和readr(大数据读取包)
- JSP与EL表达式重点学习笔记(2)
- Node.js真的无所不能?那些不适用的应用领域分析
- #!/bin/bash 与#!/bin/sh
- 客户端无法连接数据库的小问题(r8笔记第53天)
- Golang事务模型
- 厚土Go学习笔记 | 35. web服务器实现动态路径
- 数据库连接池、dbutil_知识点全掌握
- Golang 序列化之 ProtoBuf
- Golang RPC 之 gRPC
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- PHP实现微信提现功能
- PHP实现SMTP邮件的发送实例
- php实现有序数组旋转后寻找最小值办法
- PHP APP微信提现接口代码
- ThinkPHP5 的简单搭建和使用详解
- php中怎么执行linux命令详解
- phpMyAdmin通过密码漏洞留后门文件
- php 调用百度sms来发送短信的实现示例
- MySQL 8.0 新特性:快速加列
- php判断电子邮件是否正确办法
- 用Laravel Sms实现laravel短信验证码的发送的实现
- kubernetes 近期进展 - 1.14-1.19
- Kubernetes 1.19.0——cronjob
- php获取微信openid方法总结
- Laravel 关联模型-关联新增和关联更新的方法