13.3 DDPG算法综合实战:基于强化学习的股票交易策略
传统的股票交易策略通常依赖于技术分析、基本面分析和人工决策,在本节的内容中,将介绍一个综合实例,展示使用深度强化学习(DRL)方法来构建和测试一个自动化股票交易策略的过程。本项目通过引入深度强化学习,旨在自动化这一过程,从而提高交易效率并最大化投资回报。
实例13-3:深度强化学习股票交易策略(源码路径:daima\13\chatgpt-trading.ipynb)
13.3.1 项目介绍
本项目旨在展示如何利用深度强化学习(DRL)方法构建和测试一个自动化股票交易策略,通过将股票交易过程建模为马尔可夫决策过程(MDP),将交易目标定义为一个最大化问题,并使用DRL算法来训练智能代理程序,使其能够在交易环境中进行决策。
本项目的关键功能和亮点如下:
- 数据获取:使用Yahoo Finance API获取单一股票的历史价格和成交量数据。
- 数据预处理:对获取的数据进行处理,包括添加技术指标和风险度量,以供DRL模型使用。
- 环境设计:创建交易环境,包括状态空间、行动空间和奖励函数,以模拟股票交易过程。
- DRL算法实施:使用A2C、PPO、DDPG等DRL算法,对智能代理程序进行训练和验证。
- 回测策略性能:通过回测工具评估不同算法的性能,包括夏普比率、年化回报率和最大回撤等指标。
- 与市场指数比较:将策略的性能与市场指数(如道琼斯工业平均指数)进行比较,以确定策略的相对表现。
本项目为有兴趣探索自动化股票交易策略的人提供了一个有用的实例,演示了如何使用深度强化学习来构建、训练和评估交易策略的过程。本项目突出了深度强化学习在金融领域的应用潜力,以及如何使用FinRL库简化开发和测试过程。通过这个项目,我们可以更好地理解如何优化股票交易策略,提高投资回报率,并降低风险。
13.3.2 准备开发环境
本项目用到了多个Python库,其中核心库是FinRL-Library。FinRL-Library(金融强化学习库)是一个用于金融市场数据分析和交易的开源 Python 库,它专注于应用强化学习方法来解决金融领域的问题,特别是股票和加密货币市场的自动化交易。
(1)在本地安装FinRL-Library,安装命令如下所示:
pip install git+https://github.com/AI4Finance-LLC/FinRL-Library.git
(2)通过如下命令安装wrds:
pip install wrds
(3)希望在安装时忽略任何警告信息。
import warnings
warnings.filterwarnings("ignore")
(4)导入一些必要的库和模块,用于实现金融市场的数据分析和交易操作。具体代码如下所示。
# 导入必要的库
import pandas as pd # 用于数据处理
import numpy as np # 用于数值计算
import matplotlib # 用于绘图
import matplotlib.pyplot as plt # 用于绘制图表
import datetime # 用于日期和时间处理
# 魔术命令,将图表嵌入到Jupyter Notebook中
%matplotlib inline
# 导入一些自定义配置和模块
from finrl.config_tickers import DOW_30_TICKER # 导入道琼斯30成分股的配置信息
from finrl.meta.preprocessor.yahoodownloader import YahooDownloader # 导入Yahoo Finance数据下载器
from finrl.meta.preprocessor.preprocessors import FeatureEngineer, data_split # 导入特征工程和数据拆分的模块
from finrl.meta.env_stock_trading.env_stocktrading import StockTradingEnv # 导入股票交易环境
from finrl.agents.stablebaselines3.models import DRLAgent, DRLEnsembleAgent # 导入强化学习代理模型
from finrl.plot import backtest_stats, backtest_plot, get_daily_return, get_baseline # 导入绘图和回测统计相关的模块
# 导入pprint函数,用于美观地打印数据结构
from pprint import pprint
# 将自定义模块的路径添加到系统路径,以便正确导入它们
import sys
sys.path.append("../FinRL-Library")
(5)创建一个目录,用于保存训练后的强化学习模型,具体实现代码如下所示。
import os
from finrl.main import check_and_make_directories
from finrl.config import (
DATA_SAVE_DIR,
TRAINED_MODEL_DIR,
TENSORBOARD_LOG_DIR,
RESULTS_DIR,
INDICATORS,
TRAIN_START_DATE,
TRAIN_END_DATE,
TEST_START_DATE,
TEST_END_DATE,
TRADE_START_DATE,
TRADE_END_DATE,
)
check_and_make_directories([DATA_SAVE_DIR, TRAINED_MODEL_DIR, TENSORBOARD_LOG_DIR, RESULTS_DIR])
上述代码的功能如下:
- 从finrl.main中导入函数check_and_make_directories。
- 从finrl.config中导入一系列常量和配置信息,包括数据保存目录、训练模型目录、TensorBoard日志目录、结果目录、指标、训练和测试日期范围等。
- 最后,调用函数check_and_make_directories,该函数用于检查并创建指定的目录,以确保在执行后续的操作时,这些目录存在。
13.3.3 下载数据
本项目所使用的股票数据来源于Yahoo Finance,这是一个提供股票数据、财经新闻、财报等信息的网站,里面的所有数据都是免费的。FinRL使用一个名为YahooDownloader的类来从Yahoo Finance API中获取数据。在使用公共API(无需身份验证)时,每个IP地址每小时限制为2,000次请求(或每天总共最多48,000次请求),具体说明如下所示:
class YahooDownloader:
提供了从Yahoo Finance API中检索每日股票数据的方法
属性
----------
start_date : str
数据的起始日期(从config.py中修改)
end_date : str
数据的结束日期(从config.py中修改)
ticker_list : list
股票代号列表(从config.py中修改)
方法
-------
fetch_data()
从Yahoo API获取数据
(1)通过如下代码打印输出道琼斯30成分股的配置信息:
print(DOW_30_TICKER)
执行后会输出:
['AXP', 'AMGN', 'AAPL', 'BA', 'CAT', 'CSCO', 'CVX', 'GS', 'HD', 'HON', 'IBM', 'INTC', 'JNJ', 'KO', 'JPM', 'MCD', 'MMM', 'MRK', 'MSFT', 'NKE', 'PG', 'TRV', 'UNH', 'CRM', 'VZ', 'V', 'WBA', 'WMT', 'DIS', 'DOW']
(2)设置指定的日期范围,然后使用类YahooDownloader从Yahoo Finance API下载这些范围内的指定股票的数据。具体实现代码如下所示。
TRAIN_START_DATE = '2009-04-01'
TRAIN_END_DATE = '2021-01-01'
TEST_START_DATE = '2021-01-01'
TEST_END_DATE = '2022-06-01'
df = YahooDownloader(start_date = TRAIN_START_DATE,
end_date = TEST_END_DATE,
ticker_list = DOW_30_TICKER).fetch_data()
在上述代码中,使用设置的日期范围和DOW_30_TICKER(道琼斯30成分股的配置信息)作为参数,调用了YahooDownloade中的方法fetch_data()来下载相应的股票数据。下载的数据将存储在DataFrame对象df中。执行后会输出:
[*********************100%***********************] 1 of 1 completed
[*********************100%***********************] 1 of 1 completed
[*********************100%***********************] 1 of 1 completed
[*********************100%***********************] 1 of 1 completed
[*********************100%***********************] 1 of 1 completed
[*********************100%***********************] 1 of 1 completed
......
Shape of DataFrame: (96942, 8)
注意:下载的数据将包括从训练开始日期到测试结束日期的股票价格和相关信息,以供后续的分析和交易模型训练使用。
(3)显示DataFrame df 的前几行数据,以便可以查看和了解下载的股票数据的格式和内容。具体实现代码如下所示。
df.head()
执行后会输出:
date open high low close volume tic day
0 2009-04-01 3.717500 3.892857 3.710357 3.308904 589372000 AAPL 2
1 2009-04-01 48.779999 48.930000 47.099998 36.228390 10850100 AMGN 2
2 2009-04-01 13.340000 14.640000 13.080000 11.732112 27701800 AXP 2
3 2009-04-01 34.520000 35.599998 34.209999 26.850748 9288800 BA 2
4 2009-04-01 27.500000 29.520000 27.440001 19.820396 15308300 CAT 2
(4)查看DataFrame df 的末尾几行数据,具体实现代码如下所示。
df.tail()
执行后会输出:
date open high low close volume tic day
96937 2022-05-31 503.619995 504.109985 495.660004 491.949829 4003100 UNH 1
96938 2022-05-31 210.380005 214.350006 209.110001 211.322540 9586400 V 1
96939 2022-05-31 51.259998 51.560001 50.849998 49.042248 25016600 VZ 1
96940 2022-05-31 43.480000 44.270000 43.049999 42.811333 8192000 WBA 1
96941 2022-05-31 127.459999 129.899994 127.419998 127.591217 12304100 WMT 1
(5)查看DataFrame df 的形状(行数和列数),具体实现代码如下所示。
df.shape
执行后会输出:
(96942, 8)
(6)按日期和股票代号('date' 和 'tic' 列)对DataFrame df 进行排序,并查看前几行数据。具体实现代码如下所示。
df.sort_values(['date','tic']).head()
执行后会输出:
date open high low close volume tic day
0 2009-04-01 3.717500 3.892857 3.710357 3.308904 589372000 AAPL 2
1 2009-04-01 48.779999 48.930000 47.099998 36.228390 10850100 AMGN 2
2 2009-04-01 13.340000 14.640000 13.080000 11.732112 27701800 AXP 2
3 2009-04-01 34.520000 35.599998 34.209999 26.850748 9288800 BA 2
4 2009-04-01 27.500000 29.520000 27.440001 19.820396 15308300 CAT 2
(7)查看DataFrame df 中唯一的股票代号数量,具体实现代码如下所示。
len(df.tic.unique())
执行后会输出:
30
(8)查看每个股票代号在DataFrame df 中出现的次数,具体实现代码如下所示。
df.tic.value_counts()
执行后会输出:
AAPL 3315
AMGN 3315
WMT 3315
WBA 3315
VZ 3315
V 3315
UNH 3315
TRV 3315
PG 3315
NKE 3315
MSFT 3315
MRK 3315
MMM 3315
MCD 3315
KO 3315
JPM 3315
JNJ 3315
INTC 3315
IBM 3315
HON 3315
HD 3315
GS 3315
DIS 3315
CVX 3315
CSCO 3315
CRM 3315
CAT 3315
BA 3315
AXP 3315
DOW 807
Name: tic, dtype: int64
13.3.4 数据预处理
数据预处理是训练高质量机器学习模型的关键步骤,开发者需要检查缺失数据并进行特征工程,以将数据转化为适合模型训练的状态。在本项目中需要添加如下两个功能:
- 添加技术指标:在实际交易中,需要考虑各种信息,例如历史股价、当前持有股份、技术指标等。在本文中,我们演示了两个趋势跟踪技术指标:MACD 和 RSI。
- 添加动荡指数:风险厌恶程度反映了投资者是否选择保留资本。它还会影响在面对不同市场波动水平时的交易策略。为了在最坏的情况下控制风险,例如2007年至2008年的金融危机,FinRL采用了衡量极端资产价格波动的金融动荡指数。
(1)使用类FeatureEngineer进行特征工程处理,旨在准备数据以供后续的机器学习模型训练使用,确保数据质量和一致性。具体实现代码如下所示。
fe = FeatureEngineer(use_technical_indicator=True,
tech_indicator_list = INDICATORS,
use_turbulence=True,
user_defined_feature = False)
processed = fe.preprocess_data(df)
processed = processed.copy()
processed = processed.fillna(0)
processed = processed.replace(np.inf,0)
(2)使用sample()方法查看processed数据框中的随机样本,具体实现代码如下所示。
processed.sample(5)
执行后会输出:
date open high low close volume tic day macd boll_ub boll_lb rsi_30 cci_30 dx_30 close_30_sma close_60_sma turbulence
20648 2012-01-27 15.869286 16.017143 15.848929 13.616767 299709200 AAPL 4 0.333539 13.611045 12.181263 64.308950 145.852788 54.469561 12.581282 12.174724 26.745756
29227 2013-04-03 62.410000 62.750000 61.619999 53.086536 10140400 UNH 2 1.180346 52.138797 43.794426 69.621207 320.638691 67.961482 47.381937 47.454954 25.558744
73435 2019-04-24 121.349998 121.430000 118.089996 99.647766 22115000 CVX 2 -0.589889 107.941694 99.396927 45.944631 -161.852682 22.159747 104.114838 102.183287 22.350485
17687 2011-08-30 36.240002 36.490002 36.070000 21.325922 13111100 VZ 1 0.048063 21.669226 19.589475 52.227553 70.067351 0.231436 20.852927 21.028263 34.251243
18895 2011-10-28 34.259998 34.490002 34.195000 24.295948 17307400 KO 4 0.018255 24.360143 22.863088 53.045607 64.954077 3.154018 23.832205 23.950548 34.166534
13.3.5 构建环境
考虑到自动化股票交易任务的随机性和交互性质,金融任务通常被建模为马尔可夫决策过程(MDP)问题。训练过程涉及观察股票价格的变化、采取行动和计算奖励,以便使代理根据奖励来调整其策略。通过与环境的交互,交易代理将随着时间的推移制定出一种最大化回报的交易策略。
在本项目中,交易环境基于OpenAI Gym框架,根据时间驱动模拟的原则,模拟实时股票市场,使用真实市场数据。行动空间描述了代理与环境互动的允许行动,一个行动通常包括三个动作:{-1, 0, 1},其中 -1、0、1 分别表示卖出、持有和买入一股。此外,一个行动可以涉及多份股份。我们使用一个行动空间 {-k,…,-1, 0, 1, …, k},其中 k 表示要购买的股份数量,-k 表示要卖出的股份数量。例如,“购买 10 股 AAPL”或“卖出 10 股 AAPL”分别表示 10 或 -10 股。连续行动空间需要被标准化到 [-1, 1] 范围内,因为策略是在高斯分布上定义的,需要被标准化并对称化。
(1)计算与股票交易环境相关的一些维度信息,并打印出结果。具体实现代码如下所示。
stock_dimension = len(processed.tic.unique())
state_space = 1 + 2*stock_dimension + len(INDICATORS)*stock_dimension
print(f"Stock Dimension: {stock_dimension}, State Space: {state_space}")
对上述代码的具体说明如下:
- stock_dimension 表示股票的维度,它通过计算processed数据框中不同股票代号的数量来获得,即不同的股票数量。
- state_space 表示状态空间的维度,它是一个复杂的计算,包括3个组成部分:其中1表示一个时间步(t),2 * stock_dimension表示每只股票的持有股份数和现金余额的维度,len(INDICATORS) * stock_dimension表示每只股票的技术指标的维度。
- 最后,使用函数print()将股票维度和状态空间维度打印出来,以便查看这些信息。执行后会输出:
Stock Dimension: 29, State Space: 291
这些维度信息对于建立和训练股票交易的强化学习模型非常重要,因为它们确定了模型的输入和输出空间的大小。
(2)定义一个名为env_kwargs的字典,其中包含了用于配置股票交易环境的各种参数,不同的参数值可以影响模型的训练和行为。这些参数用于配置股票交易环境,以便在强化学习训练中使用。具体实现代码如下所示。
env_kwargs = {
"hmax": 100,
"initial_amount": 1000000,
"buy_cost_pct": 0.001,
"sell_cost_pct": 0.001,
"state_space": state_space,
"stock_dim": stock_dimension,
"tech_indicator_list": INDICATORS,
"action_space": stock_dimension,
"reward_scaling": 1e-4,
"print_verbosity":5
}
对各个参数的具体说明如下:
- "hmax":每个交易周期(episode)的最大时间步数,这里设置为100。
- "initial_amount":初始资金金额,这里设置为1000000。
- "buy_cost_pct":购买股票时的交易成本百分比,这里设置为0.001,表示0.1%。
- "sell_cost_pct":卖出股票时的交易成本百分比,这里同样设置为0.001。
- "state_space":状态空间的维度,之前计算的结果。
- "stock_dim":股票维度,之前计算的结果。
- "tech_indicator_list":技术指标列表,包括用于特征工程的指标。
- "action_space":行动空间的维度,等于股票维度。
- "reward_scaling":奖励缩放因子,这里设置为1e-4,用于调整奖励的大小。
- "print_verbosity":打印详细信息的级别,这里设置为5,表示较详细的打印输出。