本文概述
- 建立你的第一个财务数据自动交易程序
- 训练一些机器学习模型
- 训练决策树模型
- 关于交易的一些基本知识
- 训练物流分类器
- 训练线性回归模型
- 训练助力树
- 训练随机森林
- 一起收集所有模型
- 所有模型合计的统计
- 总结
如今, 超过60%的具有不同资产(例如股票, 指数期货, 商品)的交易活动不再由”人类”交易员进行, 而是依靠自动交易。有一些基于特定算法的专门程序可以自动在不同市场上买卖资产, 从长远来看可以获得正回报。
在本文中, 我将向你展示如何准确预测如何进行下一笔交易以获得正收益。在本例中, 我选择了标准普尔500指数作为交易的基础资产, 该指数是500家资本总额更大的美国公司的加权平均值。实施一个非常简单的策略是在华尔街交易所在上午9:30开始交易时购买标准普尔500指数, 并在东部时间下午4:00的闭市时出售该指数。如果指数的收盘价高于开盘价, 则有正收益, 而如果收盘价低于开盘价, 则将有负收益。所以问题是:我们如何知道交易时段的收盘价是否会高于开盘价?机器学习是完成如此复杂任务的有力工具, 并且可以是支持我们进行交易决策的有用工具。
机器学习是许多有用的现实生活应用程序的新领域。金融交易就是其中之一, 并且在该行业中经常使用。关于机器学习的一个重要概念是, 我们不需要为每种可能的规则(例如模式识别)编写代码。这是因为与机器学习关联的每个模型都从数据本身学习, 然后可以在以后用于预测看不见的新数据。
机器学习是许多有用的现实生活应用程序的新领域
免责声明:本文的目的是展示如何训练机器学习方法, 并且在提供的代码示例中并未解释每个功能。本文无意让一个副本复制并粘贴所有代码并运行相同的提供的测试, 因为缺少一些细节, 这些细节不在本文的讨论范围之内。另外, 需要具备Python的基础知识。本文的主要目的是展示一个示例, 说明机器学习如何有效预测金融领域的买卖。但是, 使用真实货币进行交易意味着需要具备许多其他技能, 例如货币管理和风险管理。本文只是”全局”的一小部分。
建立你的第一个财务数据自动交易程序
因此, 你想创建第一个程序来分析财务数据并预测正确的交易吗?让我告诉你怎么做。我将使用Python进行机器学习代码, 并且将使用Yahoo Finance服务的历史数据。如前所述, 在做出我们的预测之前, 需要历史数据来训练模型。
首先, 我们需要安装:
- Python, 特别是我建议使用IPython Notebook。
- 通过终端命令Yahoo Finance Python软件包(确切名称为yahoo-finance):pip install yahoo-finance。
- 名为GraphLab的机器学习软件包的免费试用版。随时检查该库的有用文档。
请注意, 只有GraphLab的一部分是开源的SFrame, 因此要使用整个库, 我们需要一个许可证。对于学生或参加Kaggle竞赛的学生, 有30天的免费许可证和非商业许可证。从我的角度来看, GraphLab Create是一个非常直观且易于使用的库, 用于分析数据和训练机器学习模型。
挖掘Python代码
让我们深入研究一些Python代码, 看看如何从Internet下载财务数据。我建议使用IPython Notebook测试以下代码, 因为与传统的IDE相比, IPython具有许多优点, 尤其是当我们需要在同一文档中将源代码, 执行代码, 表数据和图表组合在一起时。有关使用IPython Notebook的简要说明, 请参阅IPython Notebook简介文章。
因此, 让我们创建一个新的IPython笔记本并编写一些代码以下载S&P 500指数的历史价格。注意, 如果你喜欢使用其他工具, 则可以在你的首选IDE中从一个新的Python项目开始。
import graphlab as gl
from __future__ import division
from datetime import datetime
from yahoo_finance import Share
# download historical prices of S&P 500 index
today = datetime.strftime(datetime.today(), "%Y-%m-%d")
stock = Share('^GSPC') # ^GSPC is the Yahoo finance symbol to refer S&P 500 index
# we gather historical quotes from 2001-01-01 up to today
hist_quotes = stock.get_historical('2001-01-01', today)
# here is how a row looks like
hist_quotes[0]
{'Adj_Close': '2091.580078', 'Close': '2091.580078', 'Date': '2016-04-22', 'High': '2094.320068', 'Low': '2081.199951', 'Open': '2091.48999', 'Symbol': '%5eGSPC', 'Volume': '3790580000'}
在这里, hist_quotes是词典的列表, 每个词典对象都是一个交易日, 具有开盘价, 最高价, 最低价, 收盘价, 调整价, 交易量, 交易品种和日期值。在每个交易日中, 价格通常从开盘价开盘价到收盘价收盘价变化, 并达到最高和最低价高和低。我们需要通读它并创建每个最相关数据的列表。另外, 数据首先必须按最新值排序, 因此我们需要将其反转:
l_date = []
l_open = []
l_high = []
l_low = []
l_close = []
l_volume = []
# reverse the list
hist_quotes.reverse()
for quotes in hist_quotes:
l_date.append(quotes['Date'])
l_open.append(float(quotes['Open']))
l_high.append(float(quotes['High']))
l_low.append(float(quotes['Low']))
l_close.append(float(quotes['Close']))
l_volume.append(int(quotes['Volume']))
我们可以将所有下载的引号打包到一个SFrame对象中, 该对象是基于列的高度可伸缩的数据帧, 并且已压缩。优点之一是它也可以大于RAM, 因为它是磁盘支持的。你可以查看文档以了解有关SFrame的更多信息。
因此, 让我们存储然后检查历史数据:
qq = gl.SFrame({'datetime' : l_date, 'open' : l_open, 'high' : l_high, 'low' : l_low, 'close' : l_close, 'volume' : l_volume})
# datetime is a string, so convert into datetime object
qq['datetime'] = qq['datetime'].apply(lambda x:datetime.strptime(x, '%Y-%m-%d'))
# just to check if data is sorted in ascending mode
qq.head(3)
关 | 约会时间 | 高 | 低 | 打开 | 体积 |
1283.27 | 2001-01-02 00:00:00 | 1320.28 | 1276.05 | 1320.28 | 1129400000 |
1347.56 | 2001-01-03 00:00:00 | 1347.76 | 1274.62 | 1283.27 | 1880700000 |
1333.34 | 2001-01-04 00:00:00 | 1350.24 | 1329.14 | 1347.56 | 2131000000 |
现在, 我们可以使用SFrame方法save将数据保存到磁盘, 如下所示:
qq.save("SP500_daily.bin")
# once data is saved, we can use the following instruction to retrieve it
qq = gl.SFrame("SP500_daily.bin/")
让我们来看看S&P 500的样子
要查看加载的S&P 500数据的外观, 我们可以使用以下代码:
import matplotlib.pyplot as plt
%matplotlib inline # only for those who are using IPython notebook
plt.plot(qq['close'])
代码的输出如下图:
训练一些机器学习模型
增加结果
正如我在本文的介绍部分所述, 每种模型的目标都是预测收盘价是否会高于开盘价。因此, 在这种情况下, 我们可以在购买基础资产时获得正收益。因此, 我们需要在数据上添加一个结果列, 该列将成为目标变量或预测变量。此新列的每一行将是:
- 收盘价高于开盘价的Up日+1。
- -1, 表示收盘价低于开市价的下跌日。
# add the outcome variable, 1 if the trading session was positive (close>open), 0 otherwise
qq['outcome'] = qq.apply(lambda x: 1 if x['close'] > x['open'] else -1)
# we also need to add three new columns ‘ho’ ‘lo’ and ‘gain’
# they will be useful to backtest the model, later
qq['ho'] = qq['high'] - qq['open'] # distance between Highest and Opening price
qq['lo'] = qq['low'] - qq['open'] # distance between Lowest and Opening price
qq['gain'] = qq['close'] - qq['open']
由于我们需要在最后交易日之前的几天进行评估, 因此我们需要将数据滞后一天或几天。对于这种滞后操作, 我们需要GraphLab包中的另一个对象TimeSeries。 TimeSeries的方法转换使数据滞后一定数量的行。
ts = gl.TimeSeries(qq, index='datetime')
# add the outcome variable, 1 if the bar was positive (close>open), 0 otherwise
ts['outcome'] = ts.apply(lambda x: 1 if x['close'] > x['open'] else -1)
# GENERATE SOME LAGGED TIMESERIES
ts_1 = ts.shift(1) # by 1 day
ts_2 = ts.shift(2) # by 2 days
# ...etc....
# it's an arbitrary decision how many days of lag are needed to create a good forecaster, so
# everyone can experiment by his own decision
添加预测变量
预测变量是一组必须选择的特征变量, 以训练模型和预测我们的结果。因此, 预测因素的选择至关重要, 即使不是最重要的, 也是预测者的组成部分。
仅举几个例子, 要考虑的一个因素可能是今天的收盘价是否高于昨天的收盘价, 并且可能会随着前两天的收盘价而延长, 等等。类似的选择可以用以下代码翻译:
ts['feat1'] = ts['close'] > ts_1['close']
ts['feat2'] = ts['close'] > ts_2['close']
如上所示, 我在数据集(ts)上添加了两个新功能列feat1和feat2, 如果比较为true, 则包含1, 否则为0。
本文旨在给出一个应用于金融领域的机器学习示例。我更喜欢专注于如何将机器学习模型与财务数据一起使用, 并且我们不会详细讨论如何选择正确的因素来训练模型。由于复杂性的显着增加, 为什么要相对于其他因素使用某些因素的解释过于详尽。我的工作研究是研究许多选择因素以创建良好预测变量的假设。因此, 一开始, 我建议你尝试多种不同的因素组合, 以查看它们是否可以提高模型的准确性。
# add_features is a helper function, which is out of the scope of this article, # and it returns a tuple with:
# ts: a timeseries object with, in addition to the already included columns, also lagged columns
# as well as some features added to train the model, as shown above with feat1 and feat2 examples
# l_features: a list with all features used to train Classifier models
# l_lr_features: a list all features used to train Linear Regression models
ts, l_features, l_lr_features = add_features(ts)
# add the gain column, for trading operations with LONG only positions.
# The gain is the difference between Closing price - Opening price
ts['gain'] = ts['close'] - ts['open']
ratio = 0.8 # 80% of training set and 20% of testing set
training = ts.to_sframe()[0:round(len(ts)*ratio)]
testing = ts.to_sframe()[round(len(ts)*ratio):]
训练决策树模型
GraphLab Create具有一个非常干净的界面来实现机器学习模型。每个模型都有一个创建方法, 用于将模型与训练数据集拟合。典型参数为:
- 训练-这是一个训练集, 其中包含要素列和目标列。
- target-它是包含目标变量的列的名称。
- validation_set-它是用于监视模型的泛化性能的数据集。在我们的例子中, 我们没有validation_set。
- features-它是用于训练模型的要素的列名称的列表。
- 详细-如果为true, 则在训练期间打印进度信息。
而其他参数是模型本身的典型参数, 例如:
- max_depth-它是一棵树的最大深度。
通过以下代码, 我们构建了决策树:
max_tree_depth = 6
decision_tree = gl.decision_tree_classifier.create(training, validation_set=None, target='outcome', features=l_features, max_depth=max_tree_depth, verbose=False)
测量拟合模型的性能
准确性是评估预报器优劣的重要指标。它是正确预测的数量除以总数据点的数量。由于该模型装有训练数据, 因此使用训练集评估的准确性要优于使用测试集获得的准确性。
精度是肯定的肯定预测的一部分。我们需要使精度接近1, 以实现”完美”的获胜率。作为GraphLab Create程序包的另一个分类器, 我们的Decision_tree对其方法进行评估以获取拟合模型的许多重要指标。
召回量化了分类器预测正面实例的能力。召回可以解释为分类器正确识别随机选择的阳性示例的概率。我们需要精度接近1才能达到”完美”的获胜率。
以下代码将通过训练集和测试集显示拟合模型的准确性:
decision_tree.evaluate(training)['accuracy'], decision_tree.evaluate(testing)['accuracy']
(0.6077348066298343, 0.577373211963589)
如上所示, 带有测试集的模型的准确性约为57%, 这比扔硬币(50%)要好。
预测数据
GraphLab Create具有相同的界面, 可以预测来自不同拟合模型的数据。在我们的案例结果中, 我们将使用预测方法, 该方法需要一个测试集来预测目标变量。现在, 我们可以从测试集中预测数据:
predictions = decision_tree.predict(testing)
# and we add the predictions column in testing set
testing['predictions'] = predictions
# let's see the first 10 predictions, compared to real values (outcome column)
testing[['datetime', 'outcome', 'predictions']].head(10)
约会时间 | 结果 | 预测 |
2013-04-05 00:00:00 | -1 | -1 |
2013-04-08 00:00:00 | 1 | 1 |
2013-04-09 00:00:00 | 1 | 1 |
2013-04-10 00:00:00 | 1 | -1 |
2013-04-11 00:00:00 | 1 | -1 |
2013-04-12 00:00:00 | -1 | -1 |
2013-04-15 00:00:00 | -1 | 1 |
2013-04-16 00:00:00 | 1 | 1 |
2013-04-17 00:00:00 | -1 | -1 |
2013-04-18 00:00:00 | -1 | 1 |
误报是模型预测结果为正而测试集的实际结果为负的情况。反之亦然, 假阴性是模型预测阴性结果的情况, 而测试集的实际结果是阳性。
我们的交易策略等待正面预期的结果, 以开盘价购买标准普尔500并以收盘价出售, 因此我们希望具有最低的误报率以避免损失。换句话说, 我们希望我们的模型具有最高的准确率。
如我们所见, 在前10个预测值内, 有两个假阴性(分别在2013-04-10和2013-04-11)和两个假阳性(分别在2013-04-15和2013-04-18)。测试集。
通过简单的计算, 考虑以下十个预测的小集合:
- 精度= 6/10 = 0.6或60%
- 精度= 3/5 = 0.6或60%
- 召回率= 3/5 = 0.6或60%
请注意, 通常上述数字彼此不同, 但是在这种情况下它们是相同的。
回测模型
现在, 我们使用其预测值模拟模型的交易方式。如果预测的结果等于+1, 则意味着我们希望该日到来。在一天结束的时候, 我们在交易时段开始时买入该指数, 并在当天交易时段结束时卖出该指数。相反, 如果预测结果等于-1, 则我们预期将处于下跌日, 因此我们将不在该日内进行交易。
完整的日常交易(也称为往返交易)的损益(pnl)由以下公式给出:
- pnl =平仓-平仓(每个交易日)
使用下面显示的代码, 我调用辅助函数plot_equity_chart来创建一个具有累积增益曲线(权益曲线)的图表。不必太深入, 它仅获得一系列损益值并计算要绘制的一系列累积和。
pnl = testing[testing['predictions'] == 1]['gain'] # the gain column contains (Close - Open) values
# I have written a simple helper function to plot the result of all the trades applied to the
# testing set and represent the total return expressed by the index basis points
# (not expressed in dollars $)
plot_equity_chart(pnl, 'Decision tree model')
Mean of PnL is 1.843504
Sharpe is 1.972835
Round turns 511
在这里, 夏普是年度夏普比率, 它是交易模型优劣的重要指标。考虑每天表达的交易
而平均值是损益表的平均值, 而sd是标准差。为了简化上面描述的公式, 我认为无风险收益等于0。
关于交易的一些基本知识
交易指数需要购买直接来自指数的资产。许多经纪人使用称为差价合约(CFD)的衍生产品来复制标准普尔500指数, 这是双方之间交换合约开盘价和收盘价之间的差额的协议。
示例:以开盘价买入1股CFD S&P 500(价值为2000), 在当日收盘时卖出(价值为2020)。差异即增益为20点。如果每个点的价值为25美元:
- 一份CFD合约的总收益为20点x 25美元= 500美元。
假设经纪人的收入下滑了0.6点:
- 净收益为(20-0.6)点x $ 25 = $ 485。
要考虑的另一个重要方面是避免交易中的重大损失。它们可能在预测结果为+1但实际结果值为-1时发生, 因此它是一个假阳性。在这种情况下, 结束交易时段就是收盘价低于开盘价的下跌日, 我们蒙受了损失。
必须下达止损定单以防止我们在交易中可以承受的最大损失, 并且只要资产价格低于我们之前设定的固定值, 就会触发该定单。
如果我们看一下本文开头从Yahoo Finance下载的时间序列, 则每天都有低价, 这是当天达到的最低价。如果我们将止损水平设置为远离开盘价的-3点, 并且低位-开盘= -5, 则将触发止损单, 并且开仓头寸将以-3点的损失而不是-5的价格被关闭。这是降低风险的简单方法。以下代码代表我的帮助函数, 用于模拟带有止损价位的交易:
# This is a helper function to trade 1 bar (for example 1 day) with a Buy order at opening session
# and a Sell order at closing session. To protect against adverse movements of the price, a STOP order
# will limit the loss to the stop level (stop parameter must be a negative number)
# each bar must contains the following attributes:
# Open, High, Low, Close prices as well as gain = Close - Open and lo = Low - Open
def trade_with_stop(bar, slippage = 0, stop=None):
"""
Given a bar, with a gain obtained by the closing price - opening price
it applies a stop limit order to limit a negative loss
If stop is equal to None, then it returns bar['gain']
"""
bar['gain'] = bar['gain'] - slippage
if stop<>None:
real_stop = stop - slippage
if bar['lo']<=stop:
return real_stop
# stop == None
return bar['gain']
交易费用
交易成本是购买或出售证券时发生的费用。交易成本包括经纪人的佣金和点差(交易商为证券支付的价格与买方支付的价格之间的差), 如果我们想对战略进行回测, 则需要考虑它们, 类似于真实情况。当价差发生变化时, 股票交易中经常会出现滑点。在此示例中以及接下来进行的模拟中, 交易成本固定为:
- 滑点= 0.6点
- 佣金=每笔交易1美元(一轮将花费2美元)
只是写一些数字, 如果我们的总收益是10点, 1点= 25美元, 那么250美元包括交易成本, 我们的净收益将是(10-0.6)* 25-2 = 233美元。
以下代码显示止损为-3点的先前交易策略的模拟。蓝色曲线是累积收益曲线。唯一考虑的成本是打滑(0.6点), 结果以基点表示(从Yahoo Finance下载的S&P 500值的基本单位相同)。
SLIPPAGE = 0.6
STOP = -3
trades = testing[testing['predictions'] == 1][('datetime', 'gain', 'ho', 'lo', 'open', 'close')]
trades['pnl'] = trades.apply(lambda x: trade_with_stop(x, slippage=SLIPPAGE, stop=STOP))
plot_equity_chart(trades['pnl'], 'Decision tree model')
print("Slippage is %s, STOP level at %s" % (SLIPPAGE, STOP))
Mean of PnL is 2.162171
Sharpe is 3.502897
Round turns 511
Slippage is 0.6
STOP level at -3
以下代码用于以稍微不同的方式进行预测。请注意带有附加参数output_type =” probability”的预测方法。此参数用于返回预测值的概率, 而不是其类别预测(对于肯定预测的结果为+1, 对于否定预测的结果为-1)。大于或等于0.5的概率与预测值+1相关, 而小于0.5的概率值与预测值-1相关。该概率越高, 我们预测真实起床日的机会就越大。
predictions_prob = decision_tree.predict(testing, output_type = 'probability')
# predictions_prob will contain probabilities instead of the predicted class (-1 or +1)
现在, 我们使用名为backtest_ml_model的辅助函数对模型进行回测, 该函数计算一系列累积收益, 包括滑点和佣金, 并绘制其值。为简洁起见, 在没有详尽解释backtest_ml_model函数的情况下, 要强调的重要细节是, 我们不像之前的示例那样过滤那些预测结果= 1的日子, 而是过滤那些等于或大于阈值= 0.5的预报, 如下:
trades = testing[predictions_prob>=0.5][('datetime', 'gain', 'ho', 'lo', 'open', 'close')]
请记住, 每个交易日的净收益为:净收益=(总收益-滑动页)*收益-2 *佣金。
用于评估交易策略优劣的另一个重要指标是最大跌幅。通常, 它衡量的是投资组合价值从峰值到谷底的最大单次跌幅。在我们的案例中, 这是从股票曲线的最高点到最低点的最大跌幅(我们的投资组合中只有一项资产S&P 500)。因此, 给定SArray的盈亏pnl, 我们将亏损计算如下:
drawdown = pnl - pnl.cumulative_max()
max_drawdown = min(drawdown)
在辅助函数内部, 计算backtest_summary:
- 上图所示的最大亏损(以美元为单位)。
- 精度, 采用Graphlab.evaluation方法。
- 精度, 采用Graphlab.evaluation方法。
- 回想一下, 使用Graphlab.evaluation方法。
综上所述, 以下示例显示了表示模型策略累积收益的净值曲线, 所有值均以美元表示。
model = decision_tree
predictions_prob = model.predict(testing, output_type="probability")
THRESHOLD = 0.5
bt_1_1 = backtest_ml_model(testing, predictions_prob, target='outcome', threshold=THRESHOLD, STOP=-3, MULT=25, SLIPPAGE=0.6, COMMISSION=1, plot_title='DecisionTree')
backtest_summary(bt_1_1)
Mean of PnL is 54.054286
Sharpe is 3.502897
Round turns 511
Name: DecisionTree
Accuracy: 0.577373211964
Precision: 0.587084148728
Recall: 0.724637681159
Max Drawdown: -1769.00025
为了提高预测值的精度, 我们选择了一个较高的阈值, 而不是标准概率0.5(50%), 以便更加确信该模型预测到了正常工作日。
THRESHOLD = 0.55
# it’s the minimum threshold to predict an Up day so hopefully a good day to trade
bt_1_2 = backtest_ml_model(testing, predictions_prob, target='outcome', threshold=THRESHOLD, STOP=-3, MULT=25, SLIPPAGE=0.6, COMMISSION=1, plot_title='DecisionTree')
backtest_summary(bt_1_2)
Mean of PnL is 118.244689
Sharpe is 6.523478
Round turns 234
Name: DecisionTree
Accuracy: 0.560468140442
Precision: 0.662393162393
Recall: 0.374396135266
Max Drawdown: -1769.00025
从上图可以看出, 即使转弯次数较少, 权益曲线也比以前好得多(夏普是6.5而不是3.5)。
从现在开始, 我们将考虑阈值高于标准值的所有下一个模型。
训练物流分类器
我们可以像以前对决策树所做的那样, 将我们的研究应用到Logistic分类器模型中。 GraphLab Create与Logistic Classifier对象具有相同的接口, 我们将调用create方法以使用相同的参数列表构建模型。此外, 我们更喜欢预测概率向量, 而不是预测的类向量(对于阳性结果为+1, 对于阴性结果为-1), 因此我们将阈值设置为大于0.5以获得更好的精度预测。
model = gl.logistic_classifier.create(training, target='outcome', features=l_features, validation_set=None, verbose=False)
predictions_prob = model.predict(testing, 'probability')
THRESHOLD = 0.6
bt_2_2 = backtest_ml_model(testing, predictions_prob, target='outcome', threshold=THRESHOLD, STOP=-3, plot_title=model.name())
backtest_summary(bt_2_2)
Mean of PnL is 112.704215
Sharpe is 6.447859
Round turns 426
Name: LogisticClassifier
Accuracy: 0.638491547464
Precision: 0.659624413146
Recall: 0.678743961353
Max Drawdown: -1769.00025
在这种情况下, 有一个非常类似于”决策树”的摘要。毕竟, 两个模型都是分类器, 它们只能预测一类二进制结果(+ 1, -1)。
训练线性回归模型
该模型的主要区别在于, 它处理连续值而不是二进制类, 如前所述。我们不必使用等于+1的目标变量来训练模型, 而等于-1的目标天则必须是连续变量。由于我们要预测正收益, 或者说收盘价要高于开盘价, 因此现在的目标必须是我们训练集中的收益栏。此外, 要素列表必须由连续的值组成, 例如先前的”打开”, “关闭”等。
为简便起见, 我不会详细介绍如何选择正确的功能, 因为这已超出了本文的讨论范围, 而本文更倾向于展示我们应如何在数据集上应用不同的机器学习模型。传递给create方法的参数列表为:
- 训练-这是一个训练集, 其中包含要素列和目标列。
- target-它是包含目标变量的列的名称。
- validation_set-它是用于监视模型的泛化性能的数据集。在我们的例子中, 我们没有validation_set。
- features-它是用于训练模型的特征的列名称的列表, 对于此模型, 我们将使用与分类器模型有关的另一种设置。
- 详细-如果为true, 它将在训练过程中打印进度信息。
- max_iterations-它是允许通过数据的最大次数。对数据进行更多的传递会导致模型的训练更加准确。
model = gl.linear_regression.create(training, target='gain', features = l_lr_features, validation_set=None, verbose=False, max_iterations=100)
predictions = model.predict(testing)
# a linear regression model, predict continuous values, so we need to make an estimation of their
# probabilities of success and normalize all values in order to have a vector of probabilities
predictions_max, predictions_min = max(predictions), min(predictions)
predictions_prob = (predictions - predictions_min)/(predictions_max - predictions_min)
到目前为止, 我们的预测是预测增益的SArray, 而predictions_prob是预测值已标准化的SArray。为了具有良好的精度和一定的转弯次数(与以前的模型相比), 我选择了0.4作为阈值。对于predictions_prob小于0.4的情况, backtest_linear_model帮助器函数将不会开仓交易, 因为预计会出现下跌。否则, 将开启交易。
THRESHOLD = 0.4
bt_3_2 = backtest_linear_model(testing, predictions_prob, target='gain', threshold=THRESHOLD, STOP = -3, plot_title=model.name())
backtest_summary(bt_3_2)
Mean of PnL is 138.868280
Sharpe is 7.650187
Round turns 319
Name: LinearRegression
Accuracy: 0.631989596879
Precision: 0.705329153605
Recall: 0.54347826087
Max Drawdown: -1769.00025
训练助力树
就像我们之前训练决策树一样, 现在我们将训练具有与其他分类器模型相同的参数的增强树分类器。另外, 我们设置max_iterations的数量= 12, 以增加用于增强的最大迭代次数。每次迭代都会创建一个额外的树。我们还将阈值设置为大于0.5的值以提高精度。
model = gl.boosted_trees_classifier.create(training, target='outcome', features=l_features, validation_set=None, max_iterations=12, verbose=False)
predictions_prob = model.predict(testing, 'probability')
THRESHOLD = 0.7
bt_4_2 = backtest_ml_model(testing, predictions_prob, target='outcome', threshold=THRESHOLD, STOP=-3, plot_title=model.name())
backtest_summary(bt_4_2)
Mean of PnL is 112.002338
Sharpe is 6.341981
Round turns 214
Name: BoostedTreesClassifier
Accuracy: 0.563068920676
Precision: 0.682242990654
Recall: 0.352657004831
Max Drawdown: -1769.00025
训练随机森林
这是我们最后训练的模型, 即随机森林分类器, 由决策树集成而成。在模型中使用的最大树数设置为num_trees = 10, 以避免过多的复杂性和过度拟合。
model = gl.random_forest_classifier.create(training, target='outcome', features=l_features, validation_set=None, verbose=False, num_trees = 10)
predictions_prob = model.predict(testing, 'probability')
THRESHOLD = 0.6
bt_5_2 = backtest_ml_model(testing, predictions_prob, target='outcome', threshold=THRESHOLD, STOP=-3, plot_title=model.name())
backtest_summary(bt_5_2)
Mean of PnL is 114.786962
sharpe is 6.384243
Round turns 311
Name: RandomForestClassifier
Accuracy: 0.598179453836
Precision: 0.668810289389
Recall: 0.502415458937
Max Drawdown: -1769.00025
一起收集所有模型
现在, 我们可以将所有策略结合在一起, 并查看整体结果。有趣的是, 所有机器学习模型的摘要均按其精度排序。
名称 | 准确性 | 精确 | 圆转 | 锐化 |
线性回归 | 0.63 | 0.71 | 319 | 7.65 |
BoostedTreesClassifier | 0.56 | 0.68 | 214 | 6.34 |
随机森林分类器 | 0.60 | 0.67 | 311 | 6.38 |
决策树 | 0.56 | 0.66 | 234 | 6.52 |
物流分类器 | 0.64 | 0.66 | 426 | 6.45 |
如果我们收集阵列pnl中每个先前模型的所有损益, 则下图描述了逐日逐个损益之和获得的权益曲线。
Mean of PnL is 119.446463
Sharpe is 6.685744
Round turns 1504
First trading day 2013-04-09
Last trading day 2016-04-22
Total return 179647
仅给出一些数字, 用大约3年的交易, 所有模型都可获得大约18万美元的总收益。市场上最大的交易是5个CFD合约, 但是为了降低风险, 它们都在每天结束时关闭, 因此不允许隔夜头寸。
所有模型合计的统计
由于每个模型都可以建立交易, 但是我们将5个并发模型加在一起, 因此同一天可能有1个合约到5个CFD合约。如果所有模型都同意在同一天开仓交易, 则很有可能预测到上涨日。此外, 我们可以按一天的开盘时段同时开仓的模型数量进行分组。然后, 我们将精度作为并发模型数量的函数进行评估。
正如我们从上面的图表中看到的那样, 随着模型数量的确同意开仓, 精度会提高。模型越一致, 我们得到的精度就越高。例如, 当5个模型在同一天触发时, 预测正常运行一天的机会大于85%。
总结
即使在金融世界中, 机器学习也被视为一种强大的工具, 可以从数据中学习并为我们提供出色的预测工具。每个模型都显示不同的精度和精度值, 但是总的来说, 与单个模型相比, 所有模型都可以汇总以获得更好的结果。 GraphLab Create是一个很棒的库, 易于使用, 可扩展且能够非常快速地管理大数据。它实施了不同的科学和预测模型, 并且为学生和Kaggle比赛提供了免费许可证。
相关:机器学习理论及其应用简介:带有示例的可视教程
附加披露:本文仅作参考之用, 并非购买或出售要约或招揽购买任何证券或工具或参与任何特定交易策略的要约。这些网站上提供的示例仅用于教育目的。过去的结果不一定会指示未来的结果。
评论前必须登录!
注册