Python股票交易---均值回归

免责声明:本文提供的信息仅用于教育目的,不应被视为专业投资建议。在做出投资决策时进行自己的研究并谨慎行事非常重要。投资涉及风险,您做出的任何投资决定完全由您自己负责。

在本文中,您将了解什么是均值回归交易算法?如何使用 Python 来实现这一点?

将解释 3 种不同的实现:

  • 基本的
  • Z 分数
  • 统计套利

什么是均值回归交易算法?

均值回归是一种算法,表明价格倾向于恢复到其长期平均值。当股价偏离其历史平均值时,就意味着该资产被超买或超卖。然后,可能会触发交易信号来卖空或买入该工具,并期望其价格将恢复到平均值。

在下文中,您将看到均值回归算法的不同实现。

加载数据集:

在第一个和第二个实现中,我们将使用 Netflix 历史价格:

def  download_stock_data ( ticker,timestamp_start,timestamp_end ): url= f"https://query1.finance.yahoo.com/v7/finance/download/ {ticker} ?period1= {timestamp_start} &period2= {timestamp_end} &interval\ 
=1d&events =history&includeAdjustedClose=true"df = pd.read_csv(url) return df datetime_start=dt.datetime( 2022 , 1 , 1 , 7 , 35 , 51 ) 
datetime_end=dt.datetime.today() # 转换为时间戳:timestamp_start= int(datetime_start.timestamp()) 
timestamp_end= int (datetime_end.timestamp()) ticker= 'NFLX'df = download_stock_data(ticker,timestamp_start,timestamp_end) 
df = df.set_index( '日期' ) 
df.head()

实施 N°1:基本

步骤如下:

  • Netflix 20天移动平均价格计算
  • 计算价格与该移动平均线之间的差异
  • 如果差异为正,则触发卖单。当差额为负数时,就会触发买单。

一方面,如果差值为正,则意味着价格高于 20 日移动平均线。这意味着该资产已超买,它将恢复(减少)至该平均值。因此,卖出订单被触发。

另一方面,如果差值为负,意味着资产超卖,它往往会增加并达到其平均值,从而触发买入订单。

Python代码

我在这张图中绘制了价格与其 20 天移动平均线的关系:

window = 20df[ "ma_20" ] = df[ "Adj Close" ].rolling(window=window).mean() 
df[ "diff" ] = df[ "Adj Close" ] - df[ "ma_20" ] 
df [ 'signal' ] = np.where(df[ "diff" ] > 0 , - 1 , 1 ) Figs=( 8 , 4 ) df[[ 'Adj Close' , "ma_20" ]].plot(figsize=figs ) 
plt.title( "均值回归" ) 
plt.show() df[ 'diff' ].情节(无花果大小=无花果)
#我将信号乘以20能够在图表中清楚地显示出来
( 20 *df[ 'signal' ]).plot(figsize=figs, linestyle= '--' ) 
plt.title( "Diff vs Signal" ) 
plt.legend() 
plt.show() (df[ "Adj Close" ]/df[ "ma_20" ] ).plot(figsize=figs) 
plt.title( "Ratio=Close/ma_20" ) 
plt.show()

我在这张图中绘制了差异(价格 - 20 天移动平均线)和信号。它显示何时触发买入和卖出订单:

在这张图中,我绘制了价格与其移动平均线之间的比率。目标是了解该比率如何振荡。如果在 1 左右,则意味着价格正在恢复到移动平均线。我们可以清楚地看到,2022年4月有一个很大的跳跃。

局限性:

正如您所看到的,在 2022 年 4 月期间,股票价格出现了大幅下跌,并持续了几个月。如果我们遵循基本实施,就会触发买入订单。此时买入将导致接下来几天和几个月的巨大损失。这就是为什么需要将此实现与其他指标结合起来,或者选择不同的计算方法。

回测策略:

正如之前所注意到的,2022 年 4 月的价格大幅下跌严重影响了该策略的表现:

# 回测策略
# 计算每日收益
df[ 'returns' ] = df[ 'Adj Close' ].pct_change() # 计算策略收益
df[ 'strategy_returns' ] = df[ 'signal' ] .shift( 1 ) * df[ 'returns' ] # 计算累积收益
df=df.dropna() 
df[ 'cumulative_returns' ] = ( 1 + df[ 'strategy_returns' ]).cumprod() Figs = ( 8 , 4 ) 
# 绘制累积回报
df[ 'cumulative_returns' ].情节(无花果大小=无花果)
plt.title( "累计回报" ) 
plt.show()

实施 N°2:z 分数

该实现可用于量化交易算法:

  • 计算20天移动平均价
  • 计算 20 天的标准差
  • z 分数的计算方法:

如果价格穿过上限(20 天移动平均线 + n_std 标准差),则会触发卖单。这意味着该工具已超买。

如果价格低于下限(20 天移动平均线 - n_std 标准差),则会触发买入订单。

Python代码

window= 20 # 计算50日均线
df[ 'ma_20' ] = df[ 'Adj Close' ].rolling(window=window).mean() # 计算10日均线的标准差
df[ 'std_20' ] = df[ '调整关闭' ].rolling(window=window).std() # 计算 z 分数(偏离平均值的标准差数)df[ 'zscore' ] = (df[ 'Adj Close' ] - df[ 'ma_20' ]) / df[ 'std_20' ] #如果 z 分数小于 n_std (=1),则买入订单
# 如果 z 分数大于 n_std (=1),则卖出订单
# 如果在 -1 到 1 之间,则持有
n_std= 1.25df[ '信号' ] = np.where(df[ 'zscore' ] < -n_std, 1 , np.where(df[ 'zscore' ] > n_std, - 1 , 0 )) Figs=( 8 , 4 ) 
df[ 'signal' ].plot(figsize=figs, linestyle= "--" )    
df[ 'zscore' ].plot(figsize=figs)           
plt.title( "带有 z 分数的均值回归" ) 
plt.图例() 
plt.show()

在此图中,我们有 z 分数,以及买入或卖出订单的交易信号:

upper_band=df[ 'ma_20' ]+n_std*df[ 'std_20' ] 
lower_band=df[ 'ma_20' ]-n_std*df[ 'std_20' ] Figs=( 10 , 6 ) 
df[ 'Adj Close' ].plot (figsize=figs) 
df[ 'ma_20' ].plot(figsize=figs,linestyle= '-.' , color= "w" ) 
upper_band.plot(linestyle= '--' ,label= 'upper_band' ) 
lower_band.情节(线型= ':',标签= 'lower_band')
plt.fill_ Between(df.index,lower_band,upper_band,阿尔法 = 0.3 ) 
plt. 标题(“上限和下限” ) 
plt.legend() 
plt.show()

通过此图,我们可以清楚地看到价格何时超出范围。通过突破上限,股票变得超买,这是进入空头头寸的信号。

当价格下跌并突破下轨时,股票就会超卖,这可以被视为买入信号订单。

回测策略

# 计算每日收益
df[ 'returns' ] = df[ 'Adj Close' ].pct_change() # 计算策略收益
df[ 'strategy_returns' ] = df[ 'signal' ] .shift( 1 ) * df[ ' returns' ] # 计算累计收益
df=df.dropna() 
df[ 'cumulative_returns' ] = ( 1 + df[ 'strategy_returns' ]).cumprod() # 绘制累计收益
df[ 'cumulative_returns' ].plot( Figsize=figs) 
plt.title ( "累计回报" ) 
plt.show()

当 n_std=1.25 时,该策略表现出良好的性能:

尝试修改这个数字,了解它对整体性能的影响

比较

通过添加股票在触发买入或卖出订单之前必须偏离其移动平均线多少个标准差的限制,与第一段的第一次实施相比,该策略的表现变得更具吸引力。

其他

通过调整计算以适应日内价格,该实现还可用于高频交易。

  • 日内价格可以采样到几秒,甚至几毫秒。
  • 以秒为单位计算的滚动平均值和标准差
  • 如果突破上限或下限,则会触发买入或卖出订单。

实施 N°3:统计套利

在此实施中,我们将研究两只股票之间价差的均值回归:

  • 计算两只股票之间的价差
  • 计算价差的 20 天移动平均线
  • 计算价差 20 天的移动标准差
  • z 分数的计算方法:

Python代码

加载 2 只股票的数据集:Apple 和 Google:

import pandas as pd
import datetime as dtdef download_stock_data(ticker,timestamp_start,timestamp_end):url=f"https://query1.finance.yahoo.com/v7/finance/download/{ticker}?period1={timestamp_start}&period2={timestamp_end}&interval\
=1d&events=history&includeAdjustedClose=true"df = pd.read_csv(url)return df# Determine Start and End dates
datetime_start=dt.datetime(2022, 2, 8, 7, 35, 51)
datetime_end=dt.datetime.today()# Convert to timestamp:
timestamp_start=int(datetime_start.timestamp()) 
timestamp_end=int(datetime_end.timestamp()) tickers=['AAPL','GOOG']df_global=pd.DataFrame()
for ticker in tickers:df_temp = download_stock_data(ticker,timestamp_start,timestamp_end)[['Date','Adj Close']]df_temp = df_temp.set_index('Date')df_temp.columns=[ticker]df_global=pd.concat((df_global, df_temp),axis=1)
df_global.head()

指标计算

# Calculate the spread between two stocks:
ticker_long = 'AAPL'
ticker_short = 'GOOG'
spread = df_global[ticker_long] - df_global[ticker_short]window = 20
n_std = 1.5# Calculate the rolling mean and standard deviation of the spread
rolling_mean = spread.rolling(window=30).mean()
rolling_std = spread.rolling(window=30).std()# Calculate the z-score (number of standard deviations away from the rolling mean)
zscore = (spread - rolling_mean) / rolling_stdupper_band = rolling_mean + n_std * rolling_std
lower_band = rolling_mean - n_std * rolling_std

现在我们绘制不同的指标来查看价差与下限和上限的表现如何:

figs=(8,4)
plt.figure(figsize = figs)
spread.plot(label='Spread = '+ticker_long+' - '+ ticker_short,linestyle='--')
df_global[ticker_long].plot(label=ticker_long+'_price')
df_global[ticker_short].plot(label=ticker_short+'_price')
plt.title("Spread and Prices of {0} and {1}".format(ticker_long,ticker_short))
plt.legend()
plt.show()plt.figure(figsize = figs)
upper_band.plot(label='Upper_band')
lower_band .plot(label='Lower_band')
spread.plot(label = 'Spread = '+ticker_long+' - '+ ticker_short,linestyle='--', color='r')
rolling_mean.plot(label = 'ma_30days_spread', linestyle = '-.')
plt.fill_between(df_global.index,lower_band, upper_band, alpha=0.2)
plt.legend()
plt.show()

价差已突破或低于上限和下限。因此给出了买入或做空价差的交易信号:

回测策略

# Enter a long position if the z-score is less than -n_std
# Enter a short position if the z-score is greater than n_std
signal = np.where(zscore < -n_std, 1, np.where(zscore > n_std, -1, 0))
signal = pd.Series(signal, index=df_global.index)# Calculate the daily returns
returns = df_global[ticker_long].pct_change() - df_global[ticker_short].pct_change()# Calculate the strategy returns : # Shift the signal by one day to compute the returns
strategy_returns = signal.shift(1) * returns# Calculate the cumulative returns
cumulative_returns = (1 + strategy_returns).cumprod()# # Plot the cumulative returns
cumulative_returns.plot(figsize = figs)
plt.title("Cumulative Return with n_std={0}".format(n_std))
plt.show()

该策略产生的累积回报在整个期间显示出正值。

通过修改模型中的标准差数量 (n_std),您将看到对策略性能的影响。当n_std=1.25时,性能较差。

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

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

相关文章

⛳ 面试题-单例模式会存在线程安全问题吗?

&#x1f38d;目录 ⛳ 面试题-单例模式会存在线程安全问题吗&#xff1f;&#x1f3a8; 一、单例模式-简介&#x1f69c; 二、饿汉式&#x1f43e; 三、懒汉式&#x1f3af; 3.1、懒汉式&#xff1a;在调用 getInstance 的时候才创建对象。&#xff08;线程不安全&#xff09;&…

金额格式化,三位数逗号分隔,小数点后保留两位(vue金额过滤器)

金额格式化&#xff1a;三位数逗号分隔&#xff0c;小数点后保留两位 <script> // 金额格式化&#xff1a;三位数逗号分隔&#xff0c;小数点后保留两位 const payFilter (e) > {const pay parseFloat(e).toFixed(2).replace(/(\d)(?(\d{3})\.)/g, $1,)return pay…

ChatGPT癌症治疗“困难重重”,真假混讲难辨真假,准确有待提高

近年来&#xff0c;人工智能在医疗领域的应用逐渐增多&#xff0c;其中自然语言处理模型如ChatGPT在提供医疗建议和信息方面引起了广泛关注。然而&#xff0c;最新的研究表明&#xff0c;尽管ChatGPT在许多领域取得了成功&#xff0c;但它在癌症治疗方案上的准确性仍有待提高。…

leetcode 392. 判断子序列

2023.8.25 本题要判断子序列&#xff0c;可以使用动态规划来做&#xff0c;定义一个二维dp数组。 接下来就是常规的动态规划求解子序列的过程。 给出两种定义dp数组的方法。 二维bool型dp数组&#xff1a; class Solution { public:bool isSubsequence(string s, string t) …

在云原生环境中构建可扩展的大数据平台:方法和策略

文章目录 1. **选择适当的云提供商&#xff1a;**2. **采用容器化和微服务架构&#xff1a;**3. **分层架构设计&#xff1a;**4. **弹性计算资源&#xff1a;**5. **使用分布式计算框架&#xff1a;**6. **数据分区和分片&#xff1a;**7. **使用列式存储&#xff1a;**8. **缓…

qt day 1

this->setWindowIcon(QIcon("D:\\zhuomian\\wodepeizhenshi.png"));//設置窗口的iconthis->setWindowTitle("鵬哥快聊");//更改名字this->setFixedSize(500,400);//設置尺寸QLabel *qlnew QLabel(this);//創建一個標簽ql->resize(QSize(500,20…

【计算机视觉|生成对抗】用于高保真自然图像合成的大规模GAN训练用于高保真自然图像合成的大规模GAN训练(BigGAN)

本系列博文为深度学习/计算机视觉论文笔记&#xff0c;转载请注明出处 标题&#xff1a;Large Scale GAN Training for High Fidelity Natural Image Synthesis 链接&#xff1a;[1809.11096] Large Scale GAN Training for High Fidelity Natural Image Synthesis (arxiv.org…

Java 的VO、DTO、TO、BO等概念总结

当涉及到Java中的数据传输和对象封装时&#xff0c;有几个常见的概念&#xff0c;它们在不同的上下文中具有不同的用途。以下是这些概念的总结&#xff1a; VO&#xff08;Value Object&#xff09;&#xff1a; 含义&#xff1a;VO表示值对象&#xff0c;用于封装一组相关的数…

Rabbitmq消息积压问题如何解决以及如何进行限流

一、增加处理能力 优化系统架构、增加服务器资源、采用负载均衡等手段&#xff0c;以提高系统的处理能力和并发处理能力。通过增加服务器数量或者优化代码&#xff0c;确保系统能够及时处理所有的消息。 二、异步处理 将消息的处理过程设计为异步执行&#xff0c;即接收到消息…

基于机器学习的fNIRS信号质量控制方法

摘要 尽管功能性近红外光谱(fNIRS)在神经系统研究中的应用越来越广泛&#xff0c;但fNIRS信号处理仍未标准化&#xff0c;并且受到经验和手动操作的高度影响。在任何信号处理过程的开始阶段&#xff0c;信号质量控制(SQC)对于防止错误和不可靠结果至关重要。在fNIRS分析中&…

时间字符串对比

目录 需求场景 解决方案 Date对象方法 Moment.js库 Day.js库 简便方法 需求场景 在开发中&#xff0c;经常需要对比两个时间的先后顺序&#xff0c;或者计算两个时间之间的时间差。 例如&#xff1a; 在电商网站中&#xff0c;需要显示商品的上架时间和下架时间&#x…

软件工程(十一) 系统设计分类

我们知道需求规格说明书(SRS)落地之后, 就要开始着手系统设计了,看一下这个系统该如何来设计,并且如何实现。学习系统设计之前,需要先了解系统设计有哪些分类。 系统设计的分类如下 界面设计结构化设计面向对象设计(最重要)1、界面设计 界面设计也叫做人机界面设计,属于…

swift APP缓存

这里的APP缓存是指Cache文件夹里的内容&#xff0c;iOS系统从iOS 10开始就支持系统自动清理功能了。 建议重要的内容不要放到 Cache文件夹中。 一、获取缓存 /// 获取缓存大小public static func getCacheSize() -> String {let folderPath NSSearchPathForDirectoriesIn…

FreeSWITCH 1.10.10 简单图形化界面5 - 使用百度TTS

FreeSWITCH 1.10.10 简单图形化界面5 - 使用百度TTS 0、 界面预览1、注册百度AI开放平台&#xff0c;开通语音识别服务2、获取AppID/API Key/Secret Key3、 安装百度语音合成sdk4、合成代码5、在PBX中使用百度TTS6、音乐文件-TTS7、拨号规则-tts_command 0、 界面预览 http://…

SSM商城项目实战:订单管理

SSM商城项目实战&#xff1a;订单管理 在SSM商城项目中&#xff0c;订单管理是一个非常重要的功能模块。本文将详细介绍订单管理的实现思路和步骤代码。 实现SSM商城项目中订单管理功能的思路如下&#xff1a; 设计数据库表结构&#xff1a;根据订单管理的需求&#xff0c;设计…

网络有源号角(50W-100W)社区小区广播 工地语音播报,隧道广播,钢铁广播广播系统

网络有源号角&#xff08;50W-100W&#xff09;社区小区广播 工地语音播报&#xff0c;隧道广播&#xff0c;钢铁广播广播系统 SV-7042T 50W网络有源号角 SV-7042T是深圳锐科达电子有限公司的一款壁挂式网络有源号角&#xff0c;具有10/100M以太网接口&#xff0c;可将网络音…

ceph源码阅读 erasure-code

1、ceph纠删码 纠删码(Erasure Code)是比较流行的数据冗余的存储方法&#xff0c;将原始数据分成k个数据块(data chunk)&#xff0c;通过k个数据块计算出m个校验块(coding chunk)。把nkm个数据块保存在不同的节点&#xff0c;通过n中的任意k个块还原出原始数据。EC包含编码和解…

解密Spring MVC异常处理:从局部到全局,打造稳固系统的关键步骤

&#x1f600;前言 在现代软件开发中&#xff0c;异常处理是不可或缺的一部分&#xff0c;它能够有效地提高系统的稳定性和健壮性。在Spring MVC框架中&#xff0c;异常处理机制起着至关重要的作用&#xff0c;它允许开发者在程序运行过程中捕获、处理和报告异常&#xff0c;从…

Qt/C++编写视频监控系统80-远程回放视频流

一、前言 远程回放NVR或者服务器上的视频文件&#xff0c;一般有三种方式&#xff0c;第一种是调用厂家的SDK&#xff0c;这个功能最全&#xff0c;但是缺点明显就是每个厂家的设备都有自己的SDK&#xff0c;只兼容自家的设备&#xff0c;如果你的软件需要接入多个厂家的&…

【深入解读Redis系列】Redis系列(五):切片集群详解

首发博客地址 https://blog.zysicyj.top/ 系列文章地址[1] 如果 Redis 内存很大怎么办&#xff1f; 假设一台 32G 内存的服务器部署了一个 Redis&#xff0c;内存占用了 25G&#xff0c;会发生什么&#xff1f; 此时最明显的表现是 Redis 的响应变慢&#xff0c;甚至非常慢。 这…