作者:chen_h
微信号 & QQ:862251340
微信公众号:coderpai
上一篇我们研究了用一些线性模型来做股票回报预测,在这篇文章中,我们将专注于将神经网络应用于市场,从而来获得回报。
我们的目标是预测接下来 5 分钟内股票的价格变化。我们可以使用简单的前馈神经网络(FNN)。FNN的损失函数保持不变。损失函数与我们在上一篇文章中的线性回归部分中看到的相同。
J ( θ ) = 1 2 m ∑ i = 1 m ( h θ ( x i ) − y i ) 2 + α ∣ ∣ θ ∣ ∣ 2 2 J(\theta) = \frac{1}{2m}\sum^{m}_{i=1} (h_{\theta}(x^{i}) - y^{i})^{2} + \alpha||\theta||^{2}_{2} J(θ)=2m1∑i=1m(hθ(xi)−yi)2+α∣∣θ∣∣22
其中,h(x) 是上一篇文章中的线性模型,但在今天的文章中它代表 FNN。我们也使用 l2_penalty 来保持稳定性。下面是 pytorch 的代码:
class FNN(nn.Module):
def __init__(self, num_features):
super(FNN, self).__init__()
self.fc1 = nn.Linear(num_features, 100)
self.bn1 = nn.BatchNorm1d(100)
self.fc2 = nn.Linear(100, 20)
self.bn2 = nn.BatchNorm1d(20)
self.fc3 = nn.Linear(20, 1)
self.relu = nn.ReLU()
def forward(self, x):
x = self.relu(self.bn1(self.fc1(x)))
x = F.dropout(x, training=self.training)
x = self.relu(self.bn2(self.fc2(x)))
x = F.dropout(x, training=self.training)
return self.fc3(x)
我在优化模型时学到的一些东西:
将多个任务建模在一起的能力是使用神经网络的一个非常好的优势。我们的假设是特征向量包含足够的信息以便能够预测多个证券。因此,我们可以直接预测所有证券的价格变化。我们仍然使用相同的 MSE 损失函数进行优化。
class FNN(nn.Module):
def __init__(self, num_features, num_securities):
super(FNN, self).__init__()
self.fc1 = nn.Linear(num_features, 100)
self.bn1 = nn.BatchNorm1d(100)
self.fc2 = nn.Linear(100, 50)
self.bn2 = nn.BatchNorm1d(50)
self.fc3 = nn.Linear(50, num_securities)
self.relu = nn.ReLU()
def forward(self, x):
x = self.relu(self.bn1(self.fc1(x)))
x = F.dropout(x, training=self.training)
x = self.relu(self.bn2(self.fc2(x)))
x = F.dropout(x, training=self.training)
return self.fc3(x)
多任务模型的训练与普通的 FNN 模型类似。
criterion = nn.MSE()
fnn = FNN(num_features, num_securities)
l2_penalty = 1e-3
learning_rate = 1e-3
optimizer = torch.optim.Adam(fnn.parameters(), lr=1e-3, weight_decay=l2_penalty)
for n in range(num_epochs):
for i, batch in enumerate(train_loader):
inputs, targets = Variable(batch[0]), Variable(batch[1])
optimizer.zero_grad()
outputs = fnn(inputs)
loss = criterion(outputs, targets)
loss.backward()
optimizer.step()
由于 RNN 模型比较擅长预测序列,因此我们正在探索的证券预测模型可能非常适合它们。最原始的 RNN 模型会存在一个很大的问题就是梯度消失,所以我们采用 LSTM 来更好的处理这个问题。
然而,我们知道即使 LSTM 也有其自身的局限性 —— 它们通常擅长较短的序列,比如 10 到 30 的长度,所以我尝试了以下模型,长度为 15。
class LSTM(nn.Module):
def __init__(self, input_size, hidden_size, dropout=0.2):
super(LSTM, self).__init__()
self.hidden_size = hidden_size
self.rnn = nn.LSTM(
input_size=input_size,
hidden_size=hidden_size,
num_layers=1,
dropout=dropout,
bidirectional=False, )
self.fc1 = nn.Linear(hidden_size, hidden_size)
self.bn1 = nn.BatchNorm1d(hidden_size)
self.fc2 = nn.Linear(hidden_size, 1)
self.relu = nn.ReLU()
def forward(self, x):
batch_size = x.size()[0]
seq_length = x.size()[1]
x = x.view(seq_length, batch_size, -1)
# We need to pass the initial cell states
h0 = Variable(torch.zeros(seq_length, batch_size, self.hidden_size))
c0 = Variable(torch.zeros(seq_length, batch_size, self.hidden_size))
outputs, (ht, ct) = self.rnn(x, (h0, c0))
out = outputs[-1] # We are only interested in the final prediction
out = self.bn1(self.fc1(out))
out = self.relu(out)
out = F.dropout(out, training=self.training)
out = self.fc2(out)
return out
与 FNN 例子类似,我们可以将所有证券一起建模。我们只需要在 LSTM 模型中进行以下更改。
self.fc2 = nn.Linear(hidden_size, num_securities)
LSTM 与 FNN 的性能类似。但是一起学习所有证券的数据,可以很容易的管理训练好的模型。所以,我最终使用 FNN 模型来预测所有证券的价格差异。选择 FNN 主要是因为它的简单性。
此后的一项重要任务是将预测的价格变化转换为交易行为。一种流行的方法是,如果来自模型的预测信号大于特定阈值,则发送购买信号。如果信号在一段时间后低于阈值,我们可以选择持有或者卖出。
一种常见的方法是连续出现市场数据更新流。这将包括每一个相关的市场数据更新。例如,你正在交易 AAPL 股票,而你的模型包括 AAPL,MSFT,GOOGL,FB 和 AMZN,你可能希望持续流式传输每个新的订单。你可以实时计算功能并将其提供给神经网络。该模型将为 AAPL输出单个 5 分钟的预测。重要的是要记住这些预测通常是错误的。但是,我们不知道哪些是正确的。
无论如何,一旦你有了预测信号,你可以使用一个阈值来检查信号是否足够强。在预测方向上进行执行,以下是这种系统的粗略 Python 代码:
class TradingSystem(object):
def trading_logic(self, signal):
# Check if there is a BUY signal
if signal > self.threshold and self.current_risk() < self.risk_threshold:
# Send a new BUY order at the current bid price
self.send_new_order('B', self.current_bid_price)
# Cancel existing sell orders - since we have a BUY signal
self.cancel_sell_orders()
elif signal < -self.threshold and self.current_risk() > -self.risk_threshold:
# Send a new SELL order at the current ask price
self.send_new_order('S', self.current_ask_price)
# Cancel existing buy orders - since we have a SELL signal
self.cancel_buy_orders()
else:
# We may want to keep the existing orders
# or we can cancel them as well
self.cancel_all_orders()