[文献精汇]使用 LSTM Networks 的均值回归交易策略

 Backtrader 策略实例

  • [Backtrader]实例:均线策略[Backtrader] 实例:MACD策略[Backtrader] 实例:KDJ 策略
  • [Backtrader] 实例:RSI 与 EMA 结合
  • [Backtrader] 实例:SMA自定义数据源
  • [Backtrader] 实例:海龟策略[Backtrader] 实例:网格交易[Backtrader] 实例: 配对交
  • [Backtrader] 机器学习预测市场走势与回测

[介绍]([文献精汇]使用 LSTM Networks 的均值回归交易策略如何将均值回归理论与 LSTM 神经网络相结合,以创建一个交易策略。将讨论数据预处理、模型训练、策略实施和性能评估,从而避免数据泄露并使用有效的风险管理。

为什么选择均值回归和 LSTM?

了解均值回归

均值回归是一种金融策略,表明资产价格随着时间的推移趋向于其历史均值。市场参与者通过以下方式利用此策略:

  • 在价格低于平均值时购买资产。
  • 当价格超过均值时卖出。
    这个策略假设与平均值的偏差是暂时的,随着时间的推移价格会恢复到平均值(Poterba & Summers, 1988)。这种现象在各种市场和资产类别中都观察到(Balvers et al., 2000)。

了解长短期记忆(LSTM)

长短期记忆(LSTM)网络是专为序列数据设计的神经网络,例如时间序列金融数据(Hochreiter & Schmidhuber),1997)。他们擅长通过“记住”数据中的长期依赖关系来识别模式和预测未来的价格走势。以前的研究已经证明了LSTM在预测金融市场趋势方面的有效性(Fischer & Krauss,2018;Bao et al., 2017)。

准备数据

下载加密货币数据

获取过去 7 年比特币的每日价格数据,确保我们的模型有足够的历史数据。

import datetimeticker = 'BTC-USD'end_date = datetime.datetime.now()# set start_date 7 years back
start_date = end_date - datetime.timedelta(days=7*365)start_date_str = start_date.strftime('%Y-%m-%d')
end_date_str = end_date.strftime('%Y-%m-%d')# download data using yfinance with daily intervals
data = yf.download(tickers=ticker,start=start_date_str,end=end_date_str,interval='1d'
)
data.dropna(inplace=True)if data.empty:raise ValueError("No data downloaded. Please check the ticker symbol and internet connection.")
else:print("Data downloaded successfully.")

数据预处理

计算了几个捕捉价格趋势和波动性的技术指标。包括MA20、MA50、Bollinger Band、RSI、MACD、Momentum、TR、ATR。

  # calculating moving averagesdata['MA20'] = data['Close'].rolling(window=20).mean()data['MA50'] = data['Close'].rolling(window=50).mean()# calculating Bollinger Bandsdata['STD'] = data['Close'].rolling(window=20).std()data['Upper_Band'] = data['MA20'] + (data['STD'] * 2.5)data['Lower_Band'] = data['MA20'] - (data['STD'] * 2.5)# calculating %B (Bollinger Band %)data['%B'] = (data['Close'] - data['Lower_Band']) / (data['Upper_Band'] - data['Lower_Band'])# calculating RSIdelta = data['Close'].diff()up = delta.clip(lower=0)down = -1 * delta.clip(upper=0)roll_up = up.rolling(14).mean()roll_down = down.rolling(14).mean()RS = roll_up / roll_downdata['RSI'] = 100.0 - (100.0 / (1.0 + RS))# calculating MACD and Signal Lineexp1 = data['Close'].ewm(span=12, adjust=False).mean()exp2 = data['Close'].ewm(span=26, adjust=False).mean()data['MACD'] = exp1 - exp2data['Signal_Line'] = data['MACD'].ewm(span=9, adjust=False).mean()# calculating Momentumdata['Momentum'] = data['Close'] - data['Close'].shift(10)# calculating Average True Range (ATR)data['TR'] = data[['High', 'Close']].max(axis=1) - data[['Low', 'Close']].min(axis=1)data['ATR'] = data['TR'].rolling(window=14).mean()# drop rows if they have NaN valuesdata.dropna(inplace=True)

我们计算移动平均线、布林带、RSI、MACD、动量和 ATR 等技术指标。这些指标有助于捕捉趋势、动量和波动性,这对于价格预测和信号生成至关重要。

可视化技术指标

图片

Visualizing Technical Indicators

该图显示了比特币的收盘价以及 20 天和 50 天移动平均线和布林带。这有助于可视化价格趋势和波动性。

准备技术指标数据

features = ['Close', '%B', 'RSI', 'MACD', 'Signal_Line', 'Momentum', 'ATR']# feature scaling 
scaler = StandardScaler()
scaled_data = scaler.fit_transform(data[features])def create_sequences(data, seq_length):X = []y = []for i in range(seq_length, len(data)):X.append(data[i - seq_length:i])y.append(data[i, 0])  return np.array(X), np.array(y)seq_length = 60 X, y = create_sequences(scaled_data, seq_length)

我们使用 60 天的序列长度来捕获每个预测的两个月的历史数据,从而平衡足够的历史背景和计算效率。

将数据拆分为训练集和测试集

我们将数据分为训练集(5 年)和测试集(2 年),确保不会发生数据泄露。

train_size = int(5 * 365)  # 5 years for training
test_size = int(2 * 365)   # 2 years for testingX_train = X[:train_size]
y_train = y[:train_size]
X_test = X[train_size:train_size + test_size]
y_test = y[train_size:train_size + test_size]

通过将数据分为 5 年用于训练和 2 年用于测试,我们确保我们的模型在过去数据上进行训练,并在未来数据上进行测试,从而避免数据泄漏。

构建 LSTM 模型

model = Sequential()
model.add(LSTM(units=128, return_sequences=True, input_shape=(X_train.shape[1], X_train.shape[2]), kernel_regularizer=l2(0.001)))
model.add(Dropout(0.3))
model.add(LSTM(units=64, return_sequences=False, kernel_regularizer=l2(0.001)))
model.add(Dropout(0.3))
model.add(Dense(1))model.compile(optimizer='adam', loss='mean_squared_error')# early Stopping
early_stopping = EarlyStopping(monitor='val_loss', patience=5)history = model.fit(X_train,y_train,epochs=100,batch_size=32,validation_data=(X_test, y_test),callbacks=[early_stopping]
)

我们的模型从一个具有 128 个单元的 LSTM 层开始,并使用 L2 正则化来防止过拟合。我们以 0.3 的速率对正则化应用 dropout。第二个具有 64 个单元的 LSTM 层紧随其后,捕获更抽象的模式。最后,我们有一个 dense 层来生成输出。

预测评估模型

我们对测试集进行预测,并使用 MAE、MSE 和 RMSE 评估模型的性能。

predictions = model.predict(X_test)# error metrics
mae = mean_absolute_error(y_test, predictions)
mse = mean_squared_error(y_test, predictions)
rmse = np.sqrt(mse)print(f"MAE: {mae}")
print(f"MSE: {mse}")
print(f"RMSE: {rmse}")

图片

png

  • 该模型在测试集上实现了 0.1483 的平均绝对误差 (MAE) 和 0.2217 的均方根误差 (RMSE),表明预测性能合理。
  • 我们还将预测转换回原始比例。

实施交易策略

根据模型的预测和技术指标实施均值回归交易策略。

test_data = data.iloc[train_size + seq_length:train_size + seq_length + test_size].copy()
test_data['Predicted_Close'] = predicted_close
test_data['Actual_Close'] = actual_close# predicted changes calculations
test_data['Predicted_Change'] = (test_data['Predicted_Close'] - test_data['Actual_Close']) / test_data['Actual_Close']# genereate trading signals based on adjusted strategy
test_data['Signal'] = 0# adjust thresholds based on percentiles
rsi_buy_threshold = test_data['RSI'].quantile(0.4)
rsi_sell_threshold = test_data['RSI'].quantile(0.6)
predicted_change_buy_threshold = test_data['Predicted_Change'].quantile(0.6)
predicted_change_sell_threshold = test_data['Predicted_Change'].quantile(0.4)# buy signal
test_data.loc[(test_data['Predicted_Change'] > predicted_change_buy_threshold) &(test_data['RSI'] < rsi_buy_threshold),'Signal'
] = 1# sell signal
test_data.loc[(test_data['Predicted_Change'] < predicted_change_sell_threshold) &(test_data['RSI'] > rsi_sell_threshold),'Signal'
] = -1# count the number of buy and sell signals
num_buy_signals = (test_data['Signal'] == 1).sum()
num_sell_signals = (test_data['Signal'] == -1).sum()print(f"Number of Buy Signals: {num_buy_signals}")
print(f"Number of Sell Signals: {num_sell_signals}")
Number of Buy Signals: 104
Number of Sell Signals: 135

我们的策略在测试期间产生了 133 个买入信号和 142 个卖出信号。这表明该模型确定了资产相对于其预测均值被低估或高估的几个机会。

模拟交易

以 500 美元的初始资本模拟交易,包括交易成本、止损和止盈机制。

initial_capital = 500.0
positions = []
cash = initial_capital
holdings = 0
portfolio_value = []
transaction_cost = 0.0005  # let's assume 0.05% trading fee per trade
stop_loss_percent = 0.1    # 10% stop-loss
take_profit_percent = 0.2  # 20% take-profit
entry_price = Nonefor index, row in test_data.iterrows():price = row['Actual_Close']signal = row['Signal']if signal == 1 and cash > 0:# buy with a portion of cash (e.g., 50%)amount_to_buy = (cash * 0.5) * (1 - transaction_cost)holdings += amount_to_buy / pricecash -= amount_to_buyentry_price = pricepositions.append({'Date': index, 'Position': 'Buy', 'Price': price})elif signal == -1 and holdings > 0:# sell all holdingsamount_to_sell = holdings * price * (1 - transaction_cost)cash += amount_to_sellholdings = 0entry_price = Nonepositions.append({'Date': index, 'Position': 'Sell', 'Price': price})elif holdings > 0:# check for stop-loss or take-profitif price <= entry_price * (1 - stop_loss_percent):# trigger stop-lossamount_to_sell = holdings * price * (1 - transaction_cost)cash += amount_to_sellholdings = 0positions.append({'Date': index, 'Position': 'Stop Loss Sell', 'Price': price})entry_price = Noneelif price >= entry_price * (1 + take_profit_percent):# trigger take-profitamount_to_sell = holdings * price * (1 - transaction_cost)cash += amount_to_sellholdings = 0positions.append({'Date': index, 'Position': 'Take Profit Sell', 'Price': price})entry_price = Nonetotal_value = cash + holdings * priceportfolio_value.append(total_value)# musst ensure portfolio_value matches test_data length
test_data['Portfolio_Value'] = portfolio_value[:len(test_data)]

绩效指标

# calculate daily returns and cumulative returns
test_data['Daily_Return'] = test_data['Portfolio_Value'].pct_change()
test_data['Cumulative_Return'] = (1 + test_data['Daily_Return']).cumprod()# calculate annualized return
total_days = (test_data.index[-1] - test_data.index[0]).days
if total_days == 0:total_days = 1  # Avoid division by zeroannualized_return = (test_data['Cumulative_Return'].iloc[-1]) ** (365 / total_days) - 1# calculate Sharpe Ratio
returns = test_data['Daily_Return'].dropna()
if returns.std() != 0:sharpe_ratio = (returns.mean() / returns.std()) * np.sqrt(252)  # Annualized Sharpe Ratio
else:sharpe_ratio = 0.0# calculate Max Drawdown
rolling_max = test_data['Portfolio_Value'].cummax()
drawdown = test_data['Portfolio_Value'] / rolling_max - 1
max_drawdown = drawdown.min()# Print performance metrics
total_return = ((test_data['Portfolio_Value'].iloc[-1] - initial_capital) / initial_capital) * 100
print(f"Total Return: {total_return:.2f}%")
print(f"Annualized Return: {annualized_return * 100:.2f}%")
print(f"Sharpe Ratio: {sharpe_ratio:.2f}")
print(f"Max Drawdown: {max_drawdown * 100:.2f}%")
Total Return: 49.05%
Annualized Return: 26.49%
Sharpe Ratio: 0.80
Max Drawdown: -19.67%

我们的策略在两年的测试期内实现了 60.20% 的总回报率,将最初的 500 美元增长到大约 800 美元。年化回报率为 32.09%,这是可观的。0.94 的夏普比率表明相对于所承担的风险而言,回报良好。-16.88% 的最大回撤显示了在此期间最大的峰谷下跌,考虑到回报,这是可以接受的。

可视化交易信号

在 K 线图上绘制买入和卖出信号,以便更好地可视化。

# candlestick plotting
plot_data = data.loc[test_data.index][['Open', 'High', 'Low', 'Close']].copy()
plot_data.index.name = 'Date'# buy and sell signal markers for plotting
buy_signals = test_data[test_data['Signal'] == 1]
sell_signals = test_data[test_data['Signal'] == -1]

图片

png

投资组合值随时间的变化

可视化投资组合价值随时间的变化,以观察策略的表现。

plt.figure(figsize=(12, 6))
plt.plot(test_data.index, test_data['Portfolio_Value'], label='Portfolio Value')
plt.title('Portfolio Value Over Time')
plt.xlabel('Date')
plt.ylabel('Portfolio Value in USD')
plt.legend()
plt.show()

图片

png

评估性能

# performance Periods analysis
test_data['Strategy_Return'] = test_data['Portfolio_Value'].pct_change()
test_data['Rolling_Return'] = test_data['Strategy_Return'].rolling(window=30).sum()# periods of good performance
good_performance = test_data[test_data['Rolling_Return'] > 0.02]# Periods of poor performance
poor_performance = test_data[test_data['Rolling_Return'] < -0.02]# Compare our strategy with Buy-and-Hold Strategy
test_data['Buy_and_Hold'] = initial_capital * (test_data['Actual_Close'] / test_data['Actual_Close'].iloc[0])

图片

png

图片

png

结论

在本文中,我们探讨了使用应用于比特币价格数据的 LSTM 模型实现均值回归交易策略。通过在预处理数据、防止数据泄露和整合风险管理方面采取谨慎的预防措施,我们制定了一项策略,在两年内将 500 美元的初始投资转换为大约 800 美元。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/67153.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WeakAuras NES Script(lua)

WeakAuras NES Script 修星脚本字符串 脚本1&#xff1a;NES !WA:2!TMZFWXX1zDxVAs4siiRKiBN4eV(sTRKZ5Z6opYbhQQSoPtsxr(K8ENSJtS50(J3D7wV3UBF7E6hgmKOXdjKsgAvZFaPTtte0mD60XdCmmecDMKruyykDcplAZiGPfWtSsag6myGuOuq89EVDV9wPvKeGBM7U99EFVVVV33VFFB8Z2TJ8azYMlZj7Ur3QDR(…

【江协STM32】11-2/3 W25Q64简介、软件SPI读写W25Q64

1. W25Q64简介 W25Qxx系列是一种低成本、小型化、使用简单的非易失性存储器&#xff0c;常应用于数据存储、字库存储、固件程序存储等场景存储介质&#xff1a;Nor Flash&#xff08;闪存&#xff09;时钟频率&#xff1a;80MHz / 160MHz (Dual SPI) / 320MHz (Quad SPI)存储容…

沸点 | 聚焦嬴图Cloud V2.1:具备水平可扩展性+深度计算的云原生嬴图动力站!

近日&#xff0c;嬴图正式推出嬴图Cloud V2.1&#xff0c;此次发布专注于提供无与伦比的用户体验&#xff0c;包括具有水平可扩展性的嬴图Powerhouse的一键部署、具有灵活定制功能的管理控制台、VPC / 专用链接等&#xff0c;旨在满足用户不断变化需求的各项前沿功能&#xff0…

Elasticsearch入门学习

Elasticsearch是什么 Elasticsearch 是一个基于 Apache Lucene 构建的分布式搜索和分析引擎、可扩展的数据存储和矢量数据库。 它针对生产规模工作负载的速度和相关性进行了优化。 使用 Elasticsearch 近乎实时地搜索、索引、存储和分析各种形状和大小的数据。 特点 分布式&a…

重邮+数字信号处理实验六:用 MATLAB 设计 IIR 数字滤波器

一、实验目的 1、加深对 IIR 数字滤波器设计方法和设计步骤的理解&#xff1b; 2、掌握用模拟滤波器原型设计 IIR 数字滤波器的方法&#xff1b; 3、能编写 MATLAB 函数&#xff0c;掌握设计 IIR 数字滤波器的函数调用方法&#xff1b; 4、根据不同的应用场景&#xff0…

mac intel芯片下载安卓模拟器

一、调研 目前主流两个模拟器&#xff1a; 雷神模拟器 不支持macosmumu模拟器pro版 不支持macos intel芯片 搜索到mumu的Q&A中有 “Intel芯片Mac如何安装MuMu&#xff1f;” q&a&#x1f517;&#xff1a;https://mumu.163.com/mac/faq/install-on-intel-mac.html 提…

fast-crud select下拉框 实现多选功能及下拉框数据动态获取(通过接口获取)

教程 fast-crud select示例配置需求:需求比较复杂 1. 下拉框选项需要通过后端接口获取 2. 实现多选功能 由于这个前端框架使用逻辑比较复杂我也是第一次使用,所以只记录核心问题 环境:vue3,typescript,fast-crud ,elementPlus 效果 代码 // crud.tsx文件(/.ts也行 js应…

【伪随机数】关于排序算法自测如何生成随机数而引发的……

以 Random 开始 可能一开始&#xff0c;你只是写到了排序算法如何生成随机数 public static void main(String[] args) {Random random new Random();int[] nums new int[10];for (int i 0; i < nums.length; i) {nums[i] random.nextInt(100);}System.out.println(&q…

项目概述、开发环境搭建(day01)

软件开发整体介绍 软件开发流程 第1阶段: 需求分析 需求规格说明书&#xff0c; 一般来说就是使用 Word 文档来描述当前项目的各个组成部分&#xff0c;如&#xff1a;系统定义、应用环境、功能规格、性能需求等&#xff0c;都会在文档中描述。产品原型&#xff0c;一般是通过…

1Hive概览

1Hive概览 1hive简介2hive架构3hive与Hadoop的关系4hive与传统数据库对比5hive的数据存储 1hive简介 Hive是基于Hadoop的一个数据仓库工具&#xff0c;可以将结构化的数据文件映射为一张数据库表&#xff0c;并提供类SQL查询功能。 其本质是将SQL转换为MapReduce/Spark的任务进…

Hive迁移,小表(10G以下的),分区快速修复批量脚本

hive迁移要迁移元数据&#xff08;mysql&#xff09;&#xff0c;要迁移实际数据hdfs&#xff0c;迁移完后如果有分区&#xff0c;通常是不能访问的。 这里就要修复分区了&#xff0c;如果是大表&#xff0c;几十T这种&#xff0c;迁移可能花了24小时&#xff0c;那么你修复分…

Vulnhub DC-9靶机实战

前言 这里说一下这个靶机的难点 1.这次sql注入是两个库的&#xff0c;在不使用sqlmap的情况下很多人直接database()看数据库&#xff0c;另一个库反倒没关注 2.nmap的扫描方式如果用-sT的tcp连接扫端口的话是扫不到那些被防火墙过滤的端口的&#xff0c;直接nmap ip就可以 3…

快速、可靠且高性价比的定制IP模式提升芯片设计公司竞争力

作者&#xff1a;Karthik Gopal&#xff0c;SmartDV Technologies亚洲区总经理 智权半导体科技&#xff08;厦门&#xff09;有限公司总经理 无论是在出货量巨大的消费电子市场&#xff0c;还是针对特定应用的细分芯片市场&#xff0c;差异化芯片设计带来的定制化需求也在芯片…

【Git版本控制器--1】Git的基本操作--本地仓库

目录 初识git 本地仓库 认识工作区、暂存区、版本库 add操作与commit操作 master文件与commit id 修改文件 版本回退 撤销修改 删除文件 初识git Git 是一个分布式版本控制系统&#xff0c;主要用于跟踪文件的更改&#xff0c;特别是在软件开发中。 为什么要版本…

2025宝塔API一键建站系统PHP源码

源码介绍 2025宝塔API一键建站系统PHP源码&#xff0c;对接自己的支付&#xff0c;虚拟主机也能搭建&#xff0c;小白式建站系统&#xff0c;基于宝塔面板搭建的建站系统&#xff0c;功能丰富&#xff0c;多款模板&#xff0c;每日更新 上传源码到服务器&#xff0c;浏览器访问…

在IDEA上运行Java项目

新建一个项目&#xff0c;下面创建模块&#xff0c;然后在src下新建包名&#xff0c;最后见类&#xff08;class&#xff09; 设置主题 settings>apparence 设置字体 Editor> Font 设置注释 Editor>Color Scheme>Language Defaults>Comments 设置自动导包 …

2025年01月13日Github流行趋势

1. 项目名称&#xff1a;Jobs_Applier_AI_Agent 项目地址url&#xff1a;https://github.com/feder-cr/Jobs_Applier_AI_Agent项目语言&#xff1a;Python历史star数&#xff1a;25929今日star数&#xff1a;401项目维护者&#xff1a;surapuramakhil, feder-cr, cjbbb, sarob…

DHCP、MSTP+VRRP总结实验

R1即使服务器&#xff08;给予dhcp的地址的&#xff09; [LSW1]int Eth-Trunk 12 [LSW1-Eth-Trunk12]mode manual load-balance //配置链路聚合模式为手工负载分担模式 [LSW1-Eth-Trunk12]load-balance src-dst-mac //配置基于源目IP的负载分担模式[LSW1-Eth-Trunk12]trunk p…

【ArcGIS初学】产生随机点计算混淆矩阵

混淆矩阵&#xff1a;用于比较分类结果和地表真实信息 总体精度(overall accuracy) :指对角线上所有样本的像元数(正确分类的像元数)除以所有像元数。 生产者精度(producers accuracy) &#xff1a;某类中正确分类的像元数除以参考数据中该类的像元数(列方向)&#xff0c;又称…

有一台服务器可以做哪些很酷的事情

有一台服务器可以做哪些很酷的事情 今天我也来简单分享一下&#xff0c;这几年来&#xff0c;我用云服务器做了哪些有趣的事情。 服务器推荐 1. 个人博客 拥有个人服务器&#xff0c;你可以完全掌控自己的网站或博客。 与使用第三方托管平台相比&#xff0c;你能自由选择网站…