Python 金融交易实用指南(三)(2)

简介: Python 金融交易实用指南(三)

Python 金融交易实用指南(三)(1)https://developer.aliyun.com/article/1523770

图 6.10 – 比较原始价格和 ARIMA(36, 1, 2)模型预测价格的绘图

让我们使用这个拟合的模型来预测未来日期的值。首先,我们使用datetools.dates_from_range(...)方法和pandas.DataFrame.append(...)方法构建一个包含另外 4 年的日期索引且没有数据(将使用NaN值填充)的extended_dataset DataFrame,如下所示:

extended_dataset = pd.DataFrame(index=sm.tsa.datetools.dates_from_range('2020m1', length=48))
extended_dataset = dataset.append(extended_dataset)
extended_dataset
                  Price        PredPrice
2000-01-31    95.317833         0.000000
2000-02-29    100.268895       95.317901
       ...           ...             ...
2023-11-30           NaN             NaN
2023-12-31           NaN             NaN
288 rows × 2 columns

接着,我们可以再次调用ARIMAResults.predict(...)方法,为整个时间序列生成预测价格,从而对我们添加的新日期进行预测,如下所示:

extended_dataset['PredPrice'] = \
res_ar.predict(extended_dataset.index[0], 
               extended_dataset.index[-1])
extended_dataset
                  Price        PredPrice
2000-01-31     95.317833        0.000000
2000-02-29    100.268895       95.317901
       ...           ...             ...
2023-11-30           NaN      215.441777
2023-12-31           NaN      220.337355
288 rows × 2 columns

以下代码块绘制了extended_dataset DataFrame 中的最后 100 个观测值:

extended_dataset['Price'].iloc[-100:].plot(figsize=(12, 6), 
                                          color='darkgray', 
                                          linestyle='-', 
                                          lw=4, 
                                          legend='Price')
extended_dataset['PredPrice'].iloc[-100:].plot(figsize=(12, 6), 
                                        color='black', 
                                        linestyle='-.', 
                                        legend='PredPrice')

这样就得到了一个包含预测的PredPrice值的绘图,如下面的截图所示:


图 6.11 – ARIMA 模型预测的历史和预测价格

在前面截图中显示的图中,预测价格明显遵循过去价格的趋势。

使用 pmdarima 的 SARIMAX 时间序列模型

SARIMA是 ARIMA 模型的扩展,用于具有季节性成分的单变量时间序列。

SARIMAX,是模型的名称,同时支持外生变量。

这些是三个 ARIMA 参数:

  • p = 趋势自回归阶数
  • d = 趋势差分阶数
  • q = 趋势移动平均阶数

除了前面的参数之外,SARIMA 还引入了另外四个参数,如下所示:

  • P = 季节性自回归阶数
  • D = 季节性差分阶数。
  • Q = 季节性 MA 阶数。
  • m = 单个季节周期的长度,以时间步数表示。

手动查找这些参数可能会耗费时间,使用自动 ARIMA 模型可能更有优势。

在 Python 中,auto-ARIMA 建模由 pmdarima 库提供。其文档可在 alkaline-ml.com/pmdarima/index.html 上找到。

安装很简单,如下所示:

pip install pmdarima

自动 ARIMA 模型试图通过进行各种统计测试来自动发现 SARIMAX 参数,如下所示:


图 6.12 – 各种统计检验的表格。

一旦找到最佳的 d 值,auto-ARIMA 模型将在由 start_pmax_pstart_qmax_q 定义的范围内搜索最适合的模型。如果启用了 seasonal 参数,则一旦确定最佳的 D 值,我们就会使用类似的程序来找到 PQ

最佳模型通过最小化信息准则的值确定(阿卡奇信息准则 (AIC), 校正 AIC, 贝叶斯信息准则 (BIC), Hannan-Quinn 信息准则 (HQC), 或 袋外 (OOB)—用于验证评分—分别)。

如果未找到合适的模型,auto-ARIMA 将返回 ValueError 输出。

让我们使用前面的数据集进行自动 ARIMA。时间序列具有明显的季节性分量,周期为 12。

请注意下面的代码块中,我们为预测值生成了 95%的置信区间,这对于交易规则非常有用,例如,如果价格高于上限置信区间值,则卖出:

import pmdarima as pm
model = pm.auto_arima(dataset['Price'], seasonal=True, 
                      stepwise=True, m=12)
print(model.summary())
extended_dataset = \
pd.DataFrame(
    index=sm.tsa.datetools.dates_from_range('2020m1', 
    length=48))
extended_dataset['PredPrice'], conf_int = \
model.predict(48, return_conf_int=True, alpha=0.05)
plt.plot(dataset['Price'], c='blue')
plt.plot(extended_dataset['PredPrice'], c='green')
plt.show()
print(extended_dataset)
print(conf_int)

输出如下所示:


图 6.13 – SARIMAX 结果来自自动 ARIMA 的统计数据。

图中显示如下的截图:


图 6.14 – 自动 ARIMA 模型预测的历史和预测价格预测。

输出还包括预测价格,如下所示:

PredPrice
2020-01-31  194.939195
       ...         ...
2023-12-31  222.660698
[48 rows x 1 columns]

另外,输出提供了每个预测价格的置信区间,如下所示:

[[192.39868933 197.4797007 ]
 [196.80033117 202.32443987]
 [201.6275806  207.60042584]
...
 [212.45091331 225.44676173]
 [216.11548707 229.20590827]]

现在我们将看到使用 Facebook 的 Prophet 库进行时间序列预测。

使用 Facebook 的 Prophet 库进行时间序列预测。

Facebook Prophet 是一个用于预测单变量时间序列的 Python 库,对季节性和节假日效应提供了强大的支持。它特别适用于具有频繁变化趋势的时间序列,并且足够强大以处理异常值。

更具体地说,Prophet 模型是一个具有以下属性的加法回归模型:

  • 分段线性或逻辑增长趋势。
  • 年度季节性分量采用傅里叶级数模拟。
  • 用虚拟变量建模的每周季节性分量。
  • 用户提供的节假日列表

Prophet 的安装更加复杂,因为它需要编译器。 安装它的最简单方法是使用 Anaconda,如下所示:

conda install -c conda-forge fbprophet

附带的 Git 存储库包含了带有 Prophetconda 环境设置。

Prophet 库要求输入的 DataFrame 包含两列—ds 代表日期,y 代表值。

让我们将 Prophet 模型拟合到以前的数据集中。请注意在以下代码片段中,我们明确告诉 Prophet 我们希望获得每月的预测值 (freq='M'):

from fbprophet import Prophet
prophet_dataset = \
dataset.rename(columns={'Price' : 'y'}).rename_axis('ds')\
.drop('PredPrice', 1).reset_index()
print(prophet_dataset)
model = Prophet()
model.fit(prophet_dataset)
df_forecast = model.make_future_dataframe(periods=48, 
                                          freq='M')
df_forecast = model.predict(df_forecast)
print(df_forecast[['ds', 'yhat', 'yhat_lower', 
                   'yhat_upper']].tail())
model.plot(df_forecast, xlabel='Date', ylabel='Value')
model.plot_components(df_forecast)

预测值与 SARIMAX 模型非常相似,可以在此处看到:


图 6.15 – Prophet 库的输出包括预测值,以及模型组件的值

预测值存储在 yhat 列中,其中包含了 yhat_loweryhat_upper 置信区间。

Prophet 确实生成了 Prophet 组件的图表,这对于理解模型的预测能力非常有用。 一个趋势组件图表可以在这里看到:


图 6.16 – Prophet 模型的趋势组件图表

以下截图显示了年度季节性的输出:


图 6.17 – Prophet 模型的年度季节性组件图表

这是预测图表的输出:


图 6.18 – Prophet 模型的预测图表及置信区间

每个时间序列模型都略有不同,并且最适合不同类别的时间序列。 但总的来说,Prophet 模型非常稳健,并且在大多数情况下最容易使用。

scikit-learn 回归和分类简介

scikit-learn 是一个基于numpyscipy库构建的 Python 监督无监督 机器学习库。

让我们演示如何使用 scikit-learn 中的 RidgeCV 回归和分类来预测价格变化。

生成数据集

让我们从生成以下示例所需的数据集开始—一个包含了 20 年每日数据的 Pandas DataFrame,其中包含了BookPressureTradePressureRelativeValueMicrostructure字段来表示一些基于该数据集构建的合成交易信号(也被称为PriceChange字段代表我们试图预测的价格每日变化(也被称为PriceChange字段一个线性函数,并带有一些随机权重和一些随机噪声。Price字段代表使用pandas.Series.cumsum(...)方法生成的工具的实际价格。 以下代码段中可以看到代码:

import numpy as np
import pandas as pd
df = pd.DataFrame(index=pd.date_range('2000', '2020'))
df['BookPressure'] = np.random.randn(len(df)) * 2
df['TradePressure'] = np.random.randn(len(df)) * 100
df['RelativeValue'] = np.random.randn(len(df)) * 50
df['Microstructure'] = np.random.randn(len(df)) * 10
true_coefficients = np.random.randint(low=-100, high=101,
                                      size=4) / 10
df['PriceChange'] = ((df['BookPressure'] * true_coefficients[0])
+ (df['TradePressure'] * true_coefficients[1])
+ (df['RelativeValue'] * true_coefficients[2])
+ (df['Microstructure'] * true_coefficients[3])
+ (np.random.randn(len(df)) * 200))
df['Price'] = df['PriceChange'].cumsum(0) + 100000

让我们快速检查分配给我们四个特征的真实权重,如下所示:

true_coefficients
array([10\. ,  6.2, -0.9,  5\. ])

让我们还检查包含所有数据的 DataFrame,如下所示:

Df
            BookPressure  TradePressure  RelativeValue  Microstructure  PriceChange  Price
2000-01-01  4.545869  -2.335894  5.953205  -15.025576  -263.749500  99736.250500
2000-01-02  -0.302344  -186.764283  9.150213  13.795346  -758.298833  98977.951667
...    ...      ...      ...      ...      ...      ...
2019-12-31  -1.890265  -113.704752  60.258456  12.229772  -295.295108  182827.332185
2020-01-01  1.657811  -77.354049  -39.090108  -3.294086  -204.576735  182622.755450
7306 rows × 6 columns

让我们视觉检查Price字段,如下所示:

df['Price'].plot(figsize=(12, 6), color='black',
                 legend='Price')

图中显示了 20 年来以下逼真的价格演变:


图 6.19 – 合成数据集的价格图

让我们显示除Price列之外的所有列的散点矩阵,如下所示:

pd.plotting.scatter_matrix(df.drop('Price', axis=1), 
                           color='black', alpha=0.2, 
                           grid=True, diagonal='kde', 
                           figsize=(10, 10))

输出如下所示:


图 6.20 – 合成数据集的散点矩阵

散点矩阵显示PriceChangeTradePressure之间存在强关系。

在数据集上运行 RidgeCV 回归

让我们使用 scikit-learn 回归方法将线性回归模型拟合到我们的数据集。我们将使用四个特征尝试拟合和预测PriceChange字段。

首先,我们将特征和目标收集到一个 DataFrame 和一个 Series 中,如下所示:

features = df[['BookPressure', 'TradePressure', 
               'RelativeValue', 'Microstructure']]
target = df['PriceChange']

我们将使用sklearn.linear_model.RidgeCV,一个带有 L2 正则化的线性回归模型(使用 L2 范数惩罚因子以避免过拟合),该模型使用交叉验证学习最佳系数。我们将使用sklearn.linear_model.RidgeCV.fit(...)方法使用特征拟合目标值。代码如下所示:

from sklearn.linear_model import RidgeCV
ridge = RidgeCV()
ridge.fit(features, target)

结果是一个RidgeCV对象,如下所示:

RidgeCV(alphas=array([ 0.1,  1\. , 10\. ]), cv=None,
                     fit_intercept=True, gcv_mode=None, 
                     normalize=False, scoring=None, 
                     store_cv_values=False)

我们可以使用RidgeCV.coef_属性访问Ridge模型学到的权重/系数,并将其与实际系数进行比较,如下所示:

true_coefficients, ridge.coef_

模型学到的系数似乎非常接近真实权重,每个系数都有一些误差,如下所示:

(array([10\. ,  6.2, -0.9,  5\. ]),
 array([11.21856334, 6.20641632, -0.93444009, 4.94581522]))

RidgeCV.score(...)方法返回 R2 分数,表示拟合模型的准确性,如下所示:

ridge.score(features, target)

这返回以下 R2 分数,最大值为 1,因此该模型相当适合数据:

0.9076861352499385

RidgeCV.predict(...)方法输出预测的价格变化值,我们将其与pandas.Series.cumsum(...)方法相结合,生成预测的价格系列,然后将其保存在PredPrice字段中,如下所示:

df['PredPrice'] = \
ridge.predict(features).cumsum(0) + 100000; df

这将在我们的 DataFrame 中添加一个新列,如下所示:

...         Price       PredPrice
2000-01-01  ...  99736.250500    99961.011495
2000-01-02  ...  98977.951667    98862.549185
    ...     ...           ...             ...
2019-12-31  ...  182827.332185  183059.625653
2020-01-01  ...  182622.755450  182622.755450
7306 rows × 7 columns

在以下代码块中,将真实的Price字段与预测的PredPrice字段一起绘制:

df['Price'].plot(figsize=(12, 6), color='gray', 
                 linestyle='--', legend='Price')
df['PredPrice'].plot(figsize=(12, 6), color='black', 
                     linestyle='-.', legend='PredPrice')

生成的图表,如下截图所示,显示PredPrice大部分时间都跟踪Price,但在某些时间段会出现预测误差:


图 6.21 – 原始价格与 Ridge 回归模型预测价格的比较图

我们可以缩小到 2010 年第一季度,检查预测误差,如下所示:

df['Price'].loc['2010-01-01':'2010-03-31']\
.plot(figsize=(12, 6), color='darkgray', linestyle='-', 
      legend='Price')
df['PredPrice'].loc['2010-01-01':'2010-03-31']\
.plot(figsize=(12, 6), color='black', linestyle='-.', 
      legend='PredPrice')

这产生了下面的图表,显示了那段时间内 PricePredPrice 之间的差异:


图 6.22 – 比较 2010 年第一季度岭回归模型的原始价格和预测价格的图表

我们可以计算预测误差并使用密度图绘制它们,如下代码片段所示:

df['Errors'] = df['Price'] - df['PredPrice']
df['Errors'].plot(figsize=(12, 6), kind='kde', 
                  color='black', legend='Errors')

这生成了下面截图中显示的图表,展示了错误的分布:


图 6.23 – 显示岭回归模型预测误差分布的图表

前面截图显示的错误图表表明错误没有明显的偏差。

在数据集上运行分类方法

让我们演示 scikit-learn 的分类方法。

首先,我们需要为分类模型创建离散分类目标标签以进行预测。我们分别给这些条件分配 -2-1012 数值标签,并将离散目标标签保存在 target_discrete pandas.Series 对象中,如下所示:

target_discrete = pd.cut(target, bins=5, 
                         labels = \
                         [-2, -1, 0, 1, 2]).astype(int);
target_discrete

结果显示如下:

2000-01-01    0
2000-01-02   -1
            ...
2019-12-28   -1
2019-12-29    0
2019-12-30    0
2019-12-31    0
2020-01-01    0
Freq: D, Name: PriceChange, Length: 7306, dtype: int64

我们可以使用以下代码可视化五个标签的分布:

target_discrete.plot(figsize=(12, 6), kind='hist', 
                     color='black')

结果是一个频率图,如下截图所示,显示了五个标签的出现频率:


图 6.24 – 我们的离散目标-价格变化标签值 [-2, -1, 0, 1, 2] 的频率分布

对于分类,我们使用 sklearn.ensemble.RandomForestClassifier 提供的决策树分类器集合。随机森林是一种使用装袋集成方法的分类器,并通过对从原始数据集中进行带替换的随机抽样生成的数据集训练每棵树来构建决策树森林。使用 max_depth=5 参数,我们限制了每棵树的高度以减少过拟合,然后调用 RandomForestClassifier.fit(...) 方法来拟合模型,如下所示:

from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier(max_depth=5)
rf.fit(features, target_discrete)

这构建了以下 RandomForestClassifier 拟合模型:

RandomForestClassifier(
        bootstrap=True, ccp_alpha=0.0, class_weight=None,
        criterion='gini', max_depth=5, max_features='auto',
        max_leaf_nodes=None, max_samples=None,
        min_impurity_decrease=0.0, min_impurity_split=None,
        min_samples_leaf=1, min_samples_split=2,
        min_weight_fraction_leaf=0.0, n_estimators=100,
        n_jobs=None, oob_score=False, random_state=None,
        verbose=0, warm_start=False)

RandomForestClassifier.score(...) 方法返回预测与True标签的平均准确度,如下所示:

rf.score(features, target_discrete)

正如我们在这里看到的,准确度分数为 83.5%,非常好:

0.835340815767862

我们向 DataFrame 添加 DiscretePriceChangePredDiscretePriceChange 字段,以保存使用 RandomForestClassifier.predict(...) 方法的真实标签和预测标签,如下所示:

df['DiscretePriceChange'] = target_discrete
df['PredDiscretePriceChange'] = rf.predict(features)
df

结果如下 DataFrame,带有两个额外的字段:

... DiscretePriceChange PredDiscretePriceChange
2000-01-01  ...                   0                       0
2000-01-02  ...                  -1                      -1
       ...  ...                 ...                     ...
2019-12-31  ...                   0                      -1
2020-01-01  ...                   0                      -1
7306 rows × 10 columns

在下面的代码块中,我们绘制了 2010 年第一季度的两个字段:

df['DiscretePriceChange'].loc['2010-01-01':'2010-03-31'].plot(figsize=(12, 6), color='darkgray', linestyle='-', legend='DiscretePriceChange')
df['PredDiscretePriceChange'].loc['2010-01-01':'2010-03-31'].plot(figsize=(12, 6), color='black', linestyle='-.', legend='PredDiscretePriceChange')

这产生了一个图表,如下截图所示,其中True和预测标签之间存在一些错位:


图 6.25 – 2010 年 Q1 的 RandomForest 分类模型原始和预测离散价格变动标签的比较

我们可以使用以下代码计算和绘制ClassificationErrors DataFrame 的分布:

df['ClassificationErrors'] = \
df['DiscretePriceChange'] - df['PredDiscretePriceChange']
df['ClassificationErrors'].plot(figsize=(12, 6), 
                             kind='kde', color='black', 
                             legend='ClassificationErrors')

这产生了以下误差分布:


图 6.26 – RandomForest 分类器模型分类错误分布图

分类错误再次没有偏差,可以忽略不计。

摘要

所有先进的交易算法都使用统计模型,无论是用于直接交易规则还是只是决定何时进入/离开交易。在本章中,我们涵盖了 Python 的四个关键统计库——statsmodelspmdarimafbprophetscikitlearn

在下一章中,我们将讨论如何将关键的金融和经济数据导入到 Python 中。

第三部分:Python 中的算法交易

本节教你如何在 Python 中获取市场数据,如何运行基本的算法交易回测,并详细描述了关键的算法交易算法。

本节包括以下章节:

  • 第七章*,Python 中的金融市场数据访问*
  • 第八章*,Zipline 和 PyFolio 简介*
  • 第九章*,基础算法交易策略*

Python 金融交易实用指南(三)(3)https://developer.aliyun.com/article/1523774

相关文章
|
数据可视化 数据处理 Python
如何使用Python实现一个基于均线的交易策略
【10月更文挑战第9天】本文介绍了如何使用Python实现一个基于均线的交易策略。主要步骤包括导入所需库(如`pandas`、`numpy`和`matplotlib`),加载股票或期货的历史数据,计算均线和其他指标,实现交易策略逻辑,以及可视化交易结果。示例代码展示了如何根据均线交叉点进行开仓、止损和止盈操作,并提供了注意事项,如数据来源、交易成本和风险管理。
952 7
|
数据采集 数据可视化 数据挖掘
金融波动率的多模型建模研究:GARCH族与HAR模型的Python实现与对比分析
本文探讨了金融资产波动率建模中的三种主流方法:GARCH、GJR-GARCH和HAR模型,基于SPY的实际交易数据进行实证分析。GARCH模型捕捉波动率聚类特征,GJR-GARCH引入杠杆效应,HAR整合多时间尺度波动率信息。通过Python实现模型估计与性能比较,展示了各模型在风险管理、衍生品定价等领域的应用优势。
1360 66
金融波动率的多模型建模研究:GARCH族与HAR模型的Python实现与对比分析
|
存储 分布式计算 数据可视化
Python 金融编程第二版(四)(2)
Python 金融编程第二版(四)
243 0
|
存储 SQL 数据可视化
Python 金融编程第二版(四)(1)
Python 金融编程第二版(四)
206 0
|
数据采集 数据可视化 数据处理
如何使用Python实现一个交易策略。主要步骤包括:导入所需库(如`pandas`、`numpy`、`matplotlib`)
本文介绍了如何使用Python实现一个交易策略。主要步骤包括:导入所需库(如`pandas`、`numpy`、`matplotlib`),加载历史数据,计算均线和其他技术指标,实现交易逻辑,记录和可视化交易结果。示例代码展示了如何根据均线交叉和价格条件进行开仓、止损和止盈操作。实际应用时需注意数据质量、交易成本和风险管理。
966 5
|
数据采集 人工智能 自然语言处理
AI Agent 金融助理0-1 Tutorial 利用Python实时查询股票API的FinanceAgent框架构建股票(美股/A股/港股) AI Finance Agent
金融领域Finance AI Agents方面的工作,发现很多行业需求和用户输入的 query都是和查询股价/行情/指数/财报汇总/金融理财建议相关。如果需要准确的 金融实时数据就不能只依赖LLM 来生成了。常规的方案包括 RAG (包括调用API )再把对应数据和prompt 一起拼接送给大模型来做文本生成。稳定的一些商业机构的金融数据API基本都是收费的,如果是以科研和demo性质有一些开放爬虫API可以使用。这里主要介绍一下 FinanceAgent,github地址 https://github.com/AI-Hub-Admin/FinanceAgent
|
机器学习/深度学习 存储 TensorFlow
使用Python实现深度学习模型:智能金融风控与信用评估
【7月更文挑战第25天】 使用Python实现深度学习模型:智能金融风控与信用评估
11722 7
|
监控 安全 数据挖掘
Python自动化交易
【8月更文挑战第7天】随着科技发展,自动化交易成为高效智能的投资方式。Python因其实用性和灵活性,在此领域大放异彩。本文介绍使用Python进行自动化交易的流程,包括获取市场数据、制定交易策略、执行交易、风险管理、监控与优化、实时监控及通知、心态管理、安全与隐私保护以及持续学习与优化等方面,并提供了具体的代码示例。通过这些步骤,读者可以构建自己的自动化交易系统,实现稳健的投资回报。
|
机器学习/深度学习 监控 算法
Python数据分析与机器学习在金融风控中的应用
Python数据分析与机器学习在金融风控中的应用
568 12
|
数据可视化 Python
Python 金融编程第二版(三)(4)
Python 金融编程第二版(三)
135 2

推荐镜像

更多