如何使用 TensorFlow.js 预测股票价格
嗨,同行开发者们,
项目流程概述
获取股票数据
简单移动平均线
训练数据
训练神经网络
验证
预言
结论
嗨,同行开发者们,
想跟大家分享一下我的小项目,我的目标是用TensorFlow.js开发一个时间序列预测模型。在本文中,我将介绍如何通过 API 获取股票数据,进行最少的数据预处理,并让机器学习模型直接从数据中学习。希望大家喜欢!
如今,机器学习越来越受欢迎,越来越多的人将其视为预测未来走向的神奇水晶球。本实验利用人工神经网络揭示股市趋势,并展示了时间序列预测基于历史数据预测未来股价的能力。
免责声明:由于股票市场波动受多种因素影响,具有动态性和不可预测性,因此本实验仅供教育用途,绝非交易预测工具。
项目流程概述
本项目流程指南分为 4 个部分:
- 通过在线 API 获取股票数据
- 计算给定时间窗口内的简单移动平均值。
- 训练 LSTM 神经网络
- 预测并比较预测值与实际值
获取股票数据
在训练神经网络并进行任何预测之前,我们首先需要数据。我们需要的数据类型是时间序列:按时间顺序排列的数字序列。获取这些数据的一个好方法是使用Alpha Vantage 股票 API。该 API 允许我们检索过去 20 年特定公司股票价格的时间序列数据。您还可以参考这篇文章,其中解释了调整后的股票价格,这是处理历史市场数据的一个重要技术概念。
API 返回以下字段:
- 开盘价
- 当日最高价
- 当日最低价
- 收盘价(本项目中使用的是收盘价)
- 体积
为了准备神经网络的训练数据集,我们将使用股票收盘价。这也意味着我们的目标是预测未来的收盘价。下图显示了微软公司过去 20 年的每周收盘价。
简单移动平均线
在本实验中,我们使用监督学习,这意味着将数据输入神经网络,神经网络通过将输入数据映射到输出标签来进行学习。准备训练数据集的一种方法是提取时间序列数据的移动平均值。
简单移动平均线(SMA)是一种通过计算特定时间段内所有价格值的平均值来识别趋势方向的方法。时间段内的价格数量是通过实验确定的。
例如,假设过去 5 天的收盘价分别为 13、15、14、16、17,则简单移动平均线 (SMA) 为 (13+15+14+16+17)/5 = 15。因此,我们训练数据集的输入是单个时间窗口内的价格集合,其标签是这些价格的计算移动平均值。
让我们计算微软公司每周收盘价数据的简单移动平均线,窗口大小为 50。
function ComputeSMA(data, window_size)
{
let r_avgs = [], avg_prev = 0;
for (let i = 0; i <= data.length - window_size; i++){
let curr_avg = 0.00, t = i + window_size;
for (let k = i; k < t && k <= data.length; k++){
curr_avg += data[k]['price'] / window_size;
}
r_avgs.push({ set: data.slice(i, i + window_size), avg: curr_avg });
avg_prev = curr_avg;
}
return r_avgs;
}
这就是我们得到的结果:蓝色代表每周股票收盘价,橙色代表简单移动平均线(SMA)。由于SMA是50周的移动平均值,因此它比波动较大的每周价格更加平滑。
训练数据
我们可以使用每周的股票价格和计算出的简单移动平均线 (SMA) 来准备训练数据。假设窗口大小为 50,这意味着我们将使用连续 50 周的收盘价作为训练特征 (X),并将这 50 周的 SMA 作为训练标签 (Y)。如下所示……
| 排 # | 标签(Y) | 特征(X) |
|---|---|---|
| 1 | 107.9674 | [127,135.25,138.25,149.19,158.13,157.5,155.13,84.75,82.75,82.37,81.81,87.81,93,89,92.12,92.12,89.62,85.75,89.44,85.56,84.81,86.25,85.75,94.69,104.44,107.25,11 3.19,117.94,113.81,109.94,105.87,104.25,110.62,105.25,96.62,104.25,105.37,113.06,104.12,96.87,105.06,106.37,105.87,109.31,110,113.62,128.06,127.37,134,137.81] |
| 2 | 108.2624 | [135.25,138.25,149.19,158.13,157.5,155.13,84.75,82.75,82.37,81.81,87.81,93,89,92.12,92.12,89.62,85.75,89.44,85.56,84.81,86.25,85.75,94.69,104.44,107.25,113.19, 117.94,113.81,109.94,105.87,104.25,110.62,105.25,96.62,104.25,105.37,113.06,104.12,96.87,105.06,106.37,105.87,109.31,110,113.62,128.06,127.37,134,137.81,141.75] |
| 3 | 108.3312 | [138.25,149.19,158.13,157.5,155.13,84.75,82.75,82.37,81.81,87.81,93,89,92.12,92.12,89.62,85.75,89.44,85.56,84.81,86.25,85.75,94.69,104.44,107.25,113.19,117.94, 113.81,109.94,105.87,104.25,110.62,105.25,96.62,104.25,105.37,113.06,104.12,96.87,105.06,106.37,105.87,109.31,110,113.62,128.06,127.37,134,137.81,141.75,138.69] |
接下来,我们将数据分成两组:训练集和验证集。如果70%的数据用于训练,那么30%的数据用于验证。API返回的数据大约相当于1000周,因此700周用于训练,300周用于验证。
训练神经网络
现在训练数据已准备就绪,是时候创建时间序列预测模型了。为此,我们将使用TensorFlow.js框架。TensorFlow.js 是一个用于在 JavaScript 中开发和训练机器学习模型的库,我们可以将这些机器学习功能部署到 Web 浏览器中。
我们选择了一种序列模型,该模型简单地连接每一层,并在训练过程中将数据从输入传递到输出。为了使模型能够学习时间序列数据,我们创建了一个循环神经网络(RNN)层,并在RNN中添加了若干个长短期记忆网络( LSTM)单元。
该模型将使用Adam 算法(研究论文)进行训练,Adam 是一种流行的机器学习优化算法。均方根误差用于衡量预测值与实际值之间的差异,因此模型能够在训练过程中通过最小化误差来学习。
以下是上述模型的代码片段,完整代码在 Github 上。
async function trainModel(inputs, outputs, trainingsize, window_size, n_epochs, learning_rate, n_layers, callback){
const input_layer_shape = window_size;
const input_layer_neurons = 100;
const rnn_input_layer_features = 10;
const rnn_input_layer_timesteps = input_layer_neurons / rnn_input_layer_features;
const rnn_input_shape = [rnn_input_layer_features, rnn_input_layer_timesteps];
const rnn_output_neurons = 20;
const rnn_batch_size = window_size;
const output_layer_shape = rnn_output_neurons;
const output_layer_neurons = 1;
const model = tf.sequential();
let X = inputs.slice(0, Math.floor(trainingsize / 100 * inputs.length));
let Y = outputs.slice(0, Math.floor(trainingsize / 100 * outputs.length));
const xs = tf.tensor2d(X, [X.length, X[0].length]).div(tf.scalar(10));
const ys = tf.tensor2d(Y, [Y.length, 1]).reshape([Y.length, 1]).div(tf.scalar(10));
model.add(tf.layers.dense({units: input_layer_neurons, inputShape: [input_layer_shape]}));
model.add(tf.layers.reshape({targetShape: rnn_input_shape}));
let lstm_cells = [];
for (let index = 0; index < n_layers; index++) {
lstm_cells.push(tf.layers.lstmCell({units: rnn_output_neurons}));
}
model.add(tf.layers.rnn({
cell: lstm_cells,
inputShape: rnn_input_shape,
returnSequences: false
}));
model.add(tf.layers.dense({units: output_layer_neurons, inputShape: [output_layer_shape]}));
model.compile({
optimizer: tf.train.adam(learning_rate),
loss: 'meanSquaredError'
});
const hist = await model.fit(xs, ys,
{ batchSize: rnn_batch_size, epochs: n_epochs, callbacks: {
onEpochEnd: async (epoch, log) => {
callback(epoch, log);
}
}
});
return { model: model, stats: hist };
}
- 训练数据集大小(%):用于训练的数据量,剩余数据将用于验证。
- 训练轮数:数据集用于训练模型的次数(了解更多)
- 学习率:训练过程中每一步权重变化的幅度(了解更多)
- 隐藏层 LSTM:用于增加模型复杂度,以便在高维空间中学习(了解更多)
点击“开始训练模型”按钮……
该模型似乎在大约 15 个周期后收敛。
验证
模型训练完成后,就可以用它来预测未来的值了,在本例中,我们预测的是移动平均值。我们将使用 TFJS 中的 model.predict 函数。
数据已被分为两个集合:训练集和验证集。训练集用于训练模型,验证集则用于验证模型。由于模型之前未接触过验证数据集,因此如果模型能够预测出接近真实值的值,那就很好了。
因此,让我们利用剩余的数据进行预测,以便了解预测值与实际值之间的接近程度。
模型预测值(绿线)与实际价格(蓝线)的吻合度很高,表明模型能够预测之前未曾观测到的最后30%的数据。
还可以应用其他算法,并使用均方根误差来比较 2 个或多个模型的性能。
预言
最后,模型已通过验证,预测值与真实值吻合良好,我们将用它来预测未来。我们将应用相同的 model.predict 函数,并使用最近 50 个数据点作为输入,因为我们的窗口大小为 50。由于我们的训练数据每天更新,我们将使用过去 50 天的数据作为输入,来预测第 51 天的情况。
结论
除了简单的移动平均法之外,还有许多其他方法可以进行时间序列预测。未来的研究方向之一是利用来自不同来源的更多数据来实现这一目标。
借助 TensorFlow.js,在 Web 浏览器上进行机器学习成为可能,而且效果相当不错。
请在 GitHub 上查看演示,此实验仅用于教育目的,绝非交易预测工具。查看GitHub上的源代码。原文发布于jinglescode.github.io。
希望您喜欢这篇教程和代码分享。如果您能做得更好,也请与我分享。
分享这篇文章,传递一些❤️。
您或许会对《通过海报预测电影票房》这篇文章感兴趣。





