利用深度强化学习预测股价

640?wx_fmt=gif

作者介绍:王茂霖,北京航空航天大学飞行器设计专业博士在读,python、C++入门小白。个人公众号:(vvrn1_field)

       


0.总体思路

本文灵感来源于Siraj Raval的youtube频道:

https://www.youtube.com/watch?v=05NqKJ0v7EE

本文的基本思路是,利用强化Q学习,通过学习历史股价,学习在得知历史趋势的情况下,如何采取简答的买卖策略,从而获得收益,是监督学习和强化学习的一次简单结合。


1.DQN简介

DQN(deep Q learning)是将传统强化学习中Q-学习与深度神经网络相结合的一种算法。本质上是利用神经网络拟合非线性Q-table,从而解决高维的强化学习问题。DQN由DeepMind在2013年发表在arkiv上的论文“Playing Atari with Deep Reinforcement Learning”中首次提出,并在近几年不断发展,提出了DDPG等一系列改进后的算法。其基本算法思路如下图所示。

利用深度强化学习预测股价_第1张图片

DQN中有许多开创性的想法,例如local网络与target网络,Replay Buffer等,极大地提高了强化学习的效率与收敛性。著名的Alpha Go以及Alpha Zero等也是基于DQN算法开发的。2016年DeepMind提出的DDPG(深度策略梯度下降算法)在DQN的基础上引入了评价器与动作器系统,可以解决高维连续空间中的决策问题,其基本思路如下图所示,(图片来源:https://blog.csdn.net/kenneth_yu/article/details/78478356),在此不多作讨论。

利用深度强化学习预测股价_第2张图片

2.DQN代码编写

DQN代码的编写基于Pytorch框架,参考了github上udacity的深度强化学习代码,地址:(https://github.com/udacity/deep-reinforcement-learning),并在其基础上进行改进,主要分为神经网络搭建与agent创建两部分。

神经网络搭建

利用Pytorch搭建神经网络十分方便,本次搭建的神经网络输入为状态,输出为动作值,神经网络包含三个全连接层,前两层使用relu函数激活,第三层为线性连接。

# 新建一个Q神经网络
# 输入为状态,输出为动作
# 神经网络包含三个全连接层,前两层使用relu函数激活

import torch
import torch.nn as nn
import torch.nn.functional as F

class QNetwork(nn.Module):
def __init__(self, state_size, action_size, fc1_units=64, fc2_units=64):
super(QNetwork, self).__init__()
self.fc1 = nn.Linear(state_size, fc1_units)
self.fc2 = nn.Linear(fc1_units, fc2_units)
self.fc3 = nn.Linear(fc2_units, action_size)

def forward(self, state):
x = F.relu(self.fc1(state))
x = F.relu(self.fc2(x))
return self.fc3(x)


agent创建

Agent的搭建基本上按照伪代码的逻辑,获取奖励值,通过贝尔曼方程迭代,梯度下降目标网络和动作网络的差值。代码包含了Agent类和ReplayBuffer类,其中目标网络的更新参考了DDPG中的方式,使用了softupdate方法。

import numpy as np
import random
from collections import namedtuple, deque

from model import QNetwork

import torch
import torch.nn.functional as F
import torch.optim as optim

#初始化超参数
BUFFER_SIZE = int(1e5)
BATCH_SIZE = 64
GAMMA = 0.99
TAU = 1e-3
LR = 5e-4
UPDATE_EVERY = 4

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")


class ReplayBuffer:
def __init__(self, action_size, buffer_size, batch_size):# 初始化记忆库
       self.action_size = action_size
self.memory = deque(maxlen=buffer_size)
self.batch_size = batch_size
self.experience = namedtuple("Experience", field_names=["state", "action", "reward", "next_state", "done"])

def add(self, state, action, reward, next_state, done):# 向记忆库中加入一个记忆
       e = self.experience(state, action, reward, next_state, done)
self.memory.append(e)

def sample(self):# 随机取出一个minibatch
       experiences = random.sample(self.memory, k=self.batch_size)
states = torch.from_numpy(np.vstack([e.state for e in experiences if e is not None])).float().to(device)
actions = torch.from_numpy(np.vstack([e.action for e in experiences if e is not None])).float().to(device)
rewards = torch.from_numpy(np.vstack([e.reward for e in experiences if e is not None])).float().to(device)
next_states = torch.from_numpy(np.vstack([e.next_state for e in experiences if e is not None])).float().to(device)
dones = torch.from_numpy(np.vstack([e.done for e in experiences if e is not None])).float().to(device)

return (states, actions, rewards, next_states, dones)

def __len__(self):
return len(self.memory)


class Agent:

def __init__(self, state_size, action_size):
self.state_size = state_size
self.action_size = action_size

# Q-Network
       self.qnetwork_local = QNetwork(state_size, action_size).to(device)
self.qnetwork_target = QNetwork(state_size, action_size).to(device)
self.optimizer = optim.Adam(self.qnetwork_local.parameters(), lr=LR)

# Replay Buffer
       self.memory = ReplayBuffer(action_size, buffer_size=BUFFER_SIZE,batch_size=BATCH_SIZE)
# 初始化迭代步数
       self.t_step = 0
       # 初始化持仓
       self.inventory = []

def step(self, state, action, reward, next_state, done):
# 每一步需要先存储记忆库
       self.memory.add(state, action, reward, next_state, done)

# 每隔若干步学习一次
       self.t_step = (self.t_step + 1) % UPDATE_EVERY
if self.t_step == 0:
if len(self.memory) > BATCH_SIZE:
experience = self.memory.sample()
self.learn(experience, GAMMA)

def learn(self, experience, gamma):
# 更新迭代
       states, actions, rewards, next_states, dones = experience

# target network
       Q_targets_next = self.qnetwork_target(next_states).detach().max(1)[0].unsqueeze(1)
Q_targets = rewards + (gamma * Q_targets_next * (1 - dones))

Q_expected = self.qnetwork_local(states).gather(1, actions.long())

loss = F.mse_loss(Q_expected, Q_targets)
self.optimizer.zero_grad()
loss.backward()
self.optimizer.step()

self.soft_update(self.qnetwork_local, self.qnetwork_target, tau=TAU)

def soft_update(self, local_model, target_model, tau):
for target_param, local_param in zip(target_model.parameters(), local_model.parameters()):
target_param.data.copy_(tau * local_param.data + (1.0 - tau) * target_param.data)

def act(self, state, eps = 0.):
# 返回动作值
       state = torch.from_numpy(state).float().unsqueeze(0).to(device)
self.qnetwork_local.eval()
with torch.no_grad():
action_values = self.qnetwork_local(state)
self.qnetwork_local.train()

if random.random() > eps:
return np.argmax(action_values.cpu().data.numpy())
else:
return random.choice(np.arange(self.action_size))


3.学习历史股价

所有代码已经发布在我的github:https://github.com/vvrn1/stockPrediction

本次学习的股价是600967内蒙一机,因为我在这个股票上吃过甜头。。。(此处鸣谢ljm师兄)。从国泰君安交易平台将历史数据下载下来,如下图。

利用深度强化学习预测股价_第3张图片

下载数据包括十九列,包括简单的开盘价、收盘价和成交量等,以及进阶的五日均线,十日均线等数据,限于我的水平,就用十日收盘价作为状态量,即本日的操作只取决于前十日的涨跌幅。

读取数据代码如下:

stockData = []
file = open("600967.txt").read().splitlines()
# 打开数据文件
for item in file[1:]:
stockData.append(float(item.split("\t")[4]))


4.学习效果

取从2016年12月14日到2018年6月8日的历史股价作为学习样本,取2018年6月11日到2018年8月30日的历史股价作为验证样本。这种处理有一种监督学习的味道,但又不完全一样。以总收益为验证指标,此处不用收益率的原因在于模型太简单,没有设置初始投资额,也没有考虑仓位,后续模型可以在此处改进。训练1000个Episode,在我这个破本上要花大概三分钟时间,训练效果如图所示。

利用深度强化学习预测股价_第4张图片

训练效果比较符合强化学习的特征,由于Replay Buffer的不断扩充以及e-探索策略的存在,所以并不会像传统监督学习一样严格收敛,而是呈现一种震荡的收敛趋势。利用matplotlib库做可视化,可以看到基本上已经掌握了低买高卖的基本原理。

利用深度强化学习预测股价_第5张图片

取验证样本试验,得到的操作策略如图,总收益为3.29。

利用深度强化学习预测股价_第6张图片

5.结语

本次和科研无关的事情告诉大家:

投资有风险,入市需谨慎;

万般皆下品,惟有科研高。

——沃.兹基硕德


数据森麟
长按二维码关注我们






数据森麟公众号的交流群已经建立,许多小伙伴已经加入其中,感谢大家的支持。大家可以在群里交流关于数据分析&数据挖掘的相关内容,还没有加入的小伙伴可以通过扫描下方管理员二维码,让管理员帮忙拉进群,期待大家的加入。


管理员二维码:


猜你喜欢

● 

● 

● 

● 

● 


你可能感兴趣的:(利用深度强化学习预测股价)