AIPython(模型数据收盘价误差缩放)

我们探索了预测股价走势的各种方法,包括使用Facebook的先知等预测工具,季节性自动回归综合移动平均(SARIMA)模型等统计方法,多项式回归等机器学习策略,以及最终基于人工智能的循环神经网络(RNN)
在众多的人工智能模型和技术中,我们发现长期短期记忆(LSTM)模型产生了最有利的结果
LSTM模型是循环神经网络架构的变体,擅长处理序列预测挑战
与传统的前馈神经网络相反,LSTM拥有类似内存的结构,使其能够跨广泛的序列保存上下文数据
此功能使其非常适合时间序列预测、自然语言处理和其他依赖序列数据的任务
它通过缓解消失和爆炸梯度问题来解决标准RNN的根本缺陷,从而促进模型识别数据集中长期依赖性的能力
因此,LSTM已成为复杂任务的首选选项,需要长时间深入理解数据
为了证明其功效,我们开发了一个概念验证
准备步骤:安装最新的Python和PIP
创建一个带有“main.py”文件的Python项目
在项目中添加一个“数据”目录
设置并激活虚拟环境
trading-ai-lstm $ python3 -m venv venvtrading-ai-lstm $ source venv/.bin/activate(venv)交易-ai-lstm $创建一个“requirements.txt”文件
熊猫numpyscikit-learnscipymatplotlib张量流eodhdpython-dotenv确保您在虚拟环境中升级了PIP并安装依赖项
(venv) trading-ai-lstm $ pip install --upgrade pip(venv) trading-ai-lstm $ python3 -m pip install -r requirements.txt我们已经将EODHD API的API密钥包含在“.env”文件中
API_TOKEN=<YOUR_API_KEY_GOES_HERE>那应该都准备好了
如果您正在使用VSCode,并希望使用与我们相同的“.vscode/settings.json”文件,它就在这里
{"python.formatting.provider": "无","python.formatting.blackArgs": ["--line-length", "160"],"python.linting.flake8Args":["--max-line-length=160","--ignore=E203,E266,E501,W503,F403,F401,C901"],"python.analysis.diagnosticSeverityOverrides": {"reportUnusedImport": "信息","reportMissingImports": "无"},"[python]": {"editor.defaultFormatter": "ms-python.black-formatter"}}这是这个项目的GitHub存储库,以防您需要指导
构建代码第一步是您需要导入必要的库
导入osos.environ["TF_CPP_MIN_LOG_LEVEL"] = "1"进口泡菜将熊猫导入为pd导入numpy为np从dotenv导入load_dotenv从sklearn.metrics导入mean_squared_error,mean_absolute_error从 tensorflow.keras.models import Sequential从tensorflow.keras.layers导入LSTM,密集,退出从 tensorflow.keras.models 导入 load_model从sklearn.preprocessing导入MinMaxScaler将matplotlib.pyplot导入为plt从eodhd导入APIClient默认情况下,TensorFlow通常会生成大量警告和调试详细信息
我们更喜欢更干净、更有序的输出,因此我们抑制这些通知
这是在导入“os”模块后使用os.environ的特定行来实现的
训练机器学习和人工智能模型的过程需要大量的微调,主要通过所谓的超参数进行管理
这个主题错综复杂,掌握它有点像一种艺术形式
最佳超参数的选择受到各种因素的影响
根据我们通过EODHD API获得的每日标准普尔500数据,我们启动了一些广为认可的设置
鼓励您修改这些以增强结果
目前,建议将序列长度保持在20
# 可配置的超参数seq_length = 20batch_size = 64lstm_units = 50纪元=100下一步包括从我们的“.env”文件检索您的EODHD API的API_TOKEN
#从.env文件加载环境变量load_dotenv()# 检索API密钥API_TOKEN = os.getenv("API_TOKEN")如果API_TOKEN不是None: print(f"API密钥加载:{API_TOKEN[:4]}")其他: raise LookupError(“加载API密钥失败
”)
确保您拥有有效的EODHD API的API_TOKEN,以成功访问数据
我们已经建立了几个可重用的功能,并将在下面进一步使用它们时详细说明它们的功能
评论包含在这些功能中,以澄清其操作
def get_ohlc_data(use_cache: bool = False) -> pd.DataFrame:ohlcv_file = "data/ohlcv.csv" 如果使用缓存: 如果os.path.exists(ohlcv_file): 返回pd.read_csv(ohlcv_file,index_col=None) 其他:api = APIClient(API_TOKEN)df = api.get_historical_data(symbol="HSPX.LSE",interval="d",iso8601_start="2010-05-17",iso8601_end="2023-10-04",)df.to_csv(ohlcv_file,index=False) 返回df 其他:api = APIClient(API_TOKEN) 返回api.get_historical_data(symbol="HSPX.LSE",interval="d",iso8601_start="2010-05-17",iso8601_end="2023-10-04",)def create_sequences(数据,seq_length):x,y = [],[] 对于i在范围内(len(数据)-seq_length):x.append(数据[i:i + seq_length])y.append(data[i + seq_length, 3]) # 预测目标“关闭”是第4列(索引3) 返回np.array(x),np.array(y)def get_features(df: pd.DataFrame = None, feature_columns: list = ["open", "high", "low", "close", "volume"]) -> list: 返回df[feature_columns].valuesdef get_target(df: pd.DataFrame = None, target_column: str = "close") -> 列表: 返回df[target_column].valuesdef get_scaler(use_cache: bool = True) -> MinMaxScaler:scaler_file = "data/scaler.pkl" 如果使用缓存: 如果os.path.exists(scaler_file): # 加载缩放器 用open(scaler_file,“rb”)作为f: 返回pickle.load(f) 其他:缩放器 = MinMaxScaler(feature_range=(0,1)) 用open(scaler_file,“wb”)作为f:pickle.dump(缩放器,f) 返回缩放器 其他: 返回MinMaxScaler(feature_range=(0,1))def scale_features(scaler:MinMaxScaler = None,功能:列表=[]): 返回scaler.fit_transform(功能)def get_lstm_model(use_cache: bool = False) -> 顺序:model_file = "data/lstm_model.h5" 如果使用缓存: 如果os.path.exists(model_file): # 加载模型 返回load_model(model_file) 其他: # 训练LSTM模型并保存它模型=顺序()model.add(LSTM(units=lstm_units, activation='tanh', input_shape=(seq_length, 5)))model.add(退出(0.2))model.add(密集(单位=1))model.compile(optimizer="adam", loss="mean_squared_error")model.fit(x_train, y_train, epochs=epochs, batch_size=batch_size, validation_data=(x_test, y_test)) #将整个模型保存到HDF5文件中model.save(model_file) 返回模型 其他: # 训练LSTM模型模型=顺序()model.add(LSTM(units=lstm_units, activation='tanh', input_shape=(seq_length, 5)))model.add(退出(0.2))model.add(密集(单位=1))model.compile(optimizer="adam", loss="mean_squared_error")model.fit(x_train, y_train, epochs=epochs, batch_size=batch_size, validation_data=(x_test, y_test)) 返回模型def get_predicted_x_test_prices(x_test:np.ndarray = 无):predicted = model.predict(x_test) #创建一个零填充矩阵来帮助逆变换zero_filled_matrix = np.zeros((predicted.shape[0],5)) #用预测值替换zero_filled_matrix的“关闭”列zero_filled_matrix[:, 3] = np.squeeze(预测) # 执行逆变换 返回scaler.inverse_transform(zero_filled_matrix)[:, 3]def plot_x_test_actual_vs_predicted(actual_close_prices: list = [], predicted_x_test_close_prices = []) -> None: #绘制实际和预测的收盘价plt.figure(figsize=(14,7))plt.plot(actual_close_prices, label="Actual Close Prices", color="blue")plt.plot(predicted_x_test_close_prices, label="Predicted Close Prices", color="red")plt.title(“实际与预测收盘价”)plt.xlabel(“时间”)plt.ylabel(“价格”)plt.legend()plt.show()def predict_next_close(df: pd.DataFrame = None, scaler: MinMaxScaler = None) -> float: # 获取最后X天的数据并进行扩展last_x_days = df.iloc[-seq_length:][["open", "high", "low", "close", "volume"]].valueslast_x_days_scaled = scaler.transform(last_x_days) #将此数据重塑为单个序列并进行预测last_x_days_scaled = np.reshape(last_x_days_scaled, (1, seq_length, 5)) # 预测未来收盘价future_close_price = model.predict(last_x_days_scaled) #为逆变换创建一个零填充矩阵zero_filled_matrix = np.zeros((1,5)) #将预测值放在“关闭”列中(索引3)zero_filled_matrix[0, 3] = np.squeeze(future_close_price) #执行逆变换,以获得原始规模的未来价格 返回scaler.inverse_transform(zero_filled_matrix)[0, 3]def evaluate_model(x_test: list = []) -> 无: #评估模型y_pred = model.predict(x_test)mse = mean_squared_error(y_test,y_pred)mae = mean_absolute_error(y_test,y_pred)rmse = np.sqrt(mse) print(f"均方误差:{mse}") print(f"平均绝对错误:{mae}") print(f"根均方误差:{rmse}")我们想强调的一个方面是在各种函数中包含一个“use_cache”变量
该策略旨在减少对EODHD API的不必要的API调用,并避免使用相同的每日数据对模型进行冗余再培训
激活“use_cache”变量允许将数据保存到“data/”目录中的文件中
如果数据不存在,它将被生成;如果已经存在,它将被加载
当脚本多次执行时,这种方法会显著提高效率
要在每次运行时获取新数据,只需在调用函数时停用“use_cache”选项,或清除“data/”目录中的文件,即可实现相同的结果
我们现在进入代码的核心......if __name__ == "__main__": #检索3369天的标准普尔500数据df = get_ohlc_data(use_cache=True) 打印(df)最初,我们从EODHD API获取我们的OHLCV数据,并将其存入名为“df”的Pandas DataFrame中
OHLCV表示开盘、高、低、收盘和成交量,这是交易蜡烛数据的标准属性
如前所述,启用缓存可以简化流程
或者,我们还有助于在屏幕上显示这些数据
我们将一次性涵盖以下代码块......功能= get_features(df)目标 = get_target(df)缩放器=get_scaler(use_cache=True)scaled_features = scale_features(缩放器,功能)x,y = create_sequences(scaled_features,seq_length)train_size = int(0.8 len(x)) # 创建80/20%的火车/测试拆分x_train, x_test = x[:train_size], x[train_size:]y_train, y_test = y[:train_size], y[train_size:] # 重新塑造输入以适应lstm层x_train = np.reshape(x_train, (x_train.shape[0], seq_length, 5)) # 5 功能x_test = np.reshape(x_test, (x_test.shape[0], seq_length, 5)) # 5 功能“功能”包括我们将用于预测目标的输入列表,即“关闭”
“目标”包括目标值的列表,例如“关闭”
“缩放器”代表一种用于使数字正常化的方法,使它们具有可比性
例如,我们的数据集可能以接近值784开始,以3538结束
最后一行中较高的数字本质上并不意味着对预测目的具有更大的意义
标准化确保了可比性
“scaled_features”是这个缩放过程的结果,我们将用它来训练我们的人工智能模型
“x_train”和“x_test”分别表示我们将用于训练和测试人工智能模型的数据集,80/20拆分是一种常见做法
这意味着我们80%的交易数据被分配用于培训,20%被保留用于测试模型
“x”表示这些是功能或输入
“y_train”和“y_test”函数类似,但只包含目标值,例如“关闭”
最后,必须对数据进行重塑,以适应LSTM层的要求
我们开发了一个功能,要么重新训练模型,要么加载以前训练的模型
model = get_lstm_model(use_cache=True)显示的图像提供了训练序列的一瞥
您将观察到,最初,“损失”和“val_loss”指标可能不一致
然而,随着培训的进行,这些数字预计将趋同,表明取得了进展
损失:这是在训练数据集上计算的均方误差(MSE)
它反映了每个培训时代的预测标签和真实标签之间的“成本”或“错误”
目标是通过连续的时代来减少这个数字
Val_loss:这个在验证数据集上确定的均方误差,衡量模型在训练期间没有遇到的数据上的性能
它是模型推广到新的、看不见的数据的能力的指标
如果您想查看测试集上预测收盘价的列表,您可以使用此代码
predicted_x_test_close_prices = get_predicted_x_test_prices(x_test) print("Predicted 收盘价:", predicted_x_test_close_prices)就其本身而言,数据可能不是特别有启发性或直观的可视化
然而,通过将实际收盘价与预测的收盘价(请记住,这占整个数据集的20%),我们得到了更清晰的画面,如下所示
#绘制测试数据的实际和预测收盘价plot_x_test_actual_vs_predicted(df["close"].tail(len(predicted_x_test_close_prices)).values, predicted_x_test_close_prices)结果表明,该模型在测试阶段预测收盘价方面表现值得称赞
现在,转到最可能预期的方面:我们能确定明天的预测收盘价吗? # 预测下一个收盘价predicted_next_close = predict_next_close(df,缩放器) print("Predicted next 收盘价:", predicted_next_close)预测下一个收盘价:3536.906685638428这是教育目的的基本例子,标志着只是一个开始
从这里开始,您可以考虑合并额外的训练数据,调整超参数,或将模型应用于各种市场和时间间隔
如果你想评估模型,你可以包括这个
#评估模型evaluate_model(x_test)在我们的场景中,这是...均方误差:0.00021641664334765608平均绝对误差:0.01157513692221611根均方误差:0.014711106122506767来自scikit-learn的度量模块的`mean_squared_error`和`mean_absolute_error`函数分别用于计算均方误差(MSE)和均值绝对误差(MAE)
根均方误差(RMSE)是通过取MSE的平方根得出的
这些指标提供了对模型准确性的数值评估,而图形表示有助于将预测值与实际数字进行视觉比较
这些指标提供了对模型性能的定量评估,而情节有助于在视觉上比较预测值和实际数字
AIPython(模型数据收盘价误差缩放)
(图片来源网络,侵删)

联系我们

在线咨询:点击这里给我发消息