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

news2024/11/24 10:18:52

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

在本文中,您将了解什么是均值回归交易算法?如何使用 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 = 20

 df[ "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.25
 df[ '信号' ] = 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 dt

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

# 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_std

upper_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.coloradmin.cn/o/948284.html

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

相关文章

你的香港公司开始年审了吗?

小青是个SOHO&#xff0c;在19年找A注册的香港公司&#xff0c;一开始是想着有个自己的公司收款或者给客户做合同的时候不需要麻烦供应商&#xff0c;会相对方便一些。公司下来之后&#xff0c;每年年审的费用也就上千块&#xff0c;还不算太高。 一开始做年审&#xff0c;都是…

Rn实现省市区三级联动

省市区三级联动选择是个很频繁的需求&#xff0c;但是查看了市面上很多插件不是太老不维护就是不满足需求&#xff0c;就试着实现一个 这个功能无任何依赖插件 功能略简单&#xff0c;但能实现需求 核心代码也尽力控制在了60行左右 pca-code.json树型数据来源 Administrative-d…

基于RabbitMQ的模拟消息队列之三——硬盘数据管理

文章目录 一、数据库管理1.设计数据库2.添加sqlite依赖3.配置application.properties文件4.创建接口MetaMapper5.创建MetaMapper.xml文件6.数据库操作7.封装数据库操作 二、文件管理1.消息持久化2.消息文件格式3.序列化/反序列化4.创建文件管理类MessageFileManager5.垃圾回收 …

【校招VIP】测试计划之测试分类

考点介绍&#xff1a; 本专题主要介绍了软件测试在不同场景下的划分。并且讲解了基于软件测试的划分衍生出的常见面试题。 测试分类也是校招里面考察的一个重点。 『测试计划之测试分类』相关题目及解析内容可点击文章末尾链接查看&#xff01; 一、考点试题 1.软件测试按开…

【安卓】拿注册码的两种方式

【安卓】拿注册码的两种方式 文章仅用于学习交流&#xff0c;请勿利用文章中的技术对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失&#xff0c;均由使用者本人负责。首发吾爱&#xff1a;https://www.52pojie.cn/thread-1826802-1-1.html言归…

OBS Studio 30.0 承诺在 Linux 上支持英特尔 QSV,为 DeckLink 提供 HDR 回放功能

导读OBS Studio 30.0 现已推出公开测试版&#xff0c;承诺为这款广受欢迎的免费开源截屏和流媒体应用程序提供多项令人兴奋的新功能&#xff0c;以及大量其他更改和错误修复。 OBS Studio 30.0 承诺在 Linux 上支持英特尔 QSV&#xff08;快速同步视频&#xff09;、WHIP/WebRT…

Makefile介绍与使用

Make简介 工程管理器&#xff0c;顾名思义&#xff0c;是指管理较多的文件 Make工程管理器也就是个“”自动编译管理器”&#xff0c;这里的“自动”是指它能够根据文件时间戳自动发现更新过的文件而减少编译的工作量&#xff0c;同事&#xff0c;它通过读入Makefile文件的内…

问道管理:市场热点有望轮动表现 关注数据要素等主题板块

近期两市指数继续单边下行趋势仍未扭转&#xff0c;短期利好后指数虽有反弹&#xff0c;但上方仍然压力重重&#xff0c;短期或仍然以反复筑底为主。因而&#xff0c;在国内根本面仍未强势复苏前&#xff0c;指数技能面上仍然会有限制&#xff0c;短期反弹修正后或仍有反复&…

RNN循环神经网络

目录 一、卷积核与循环核 二、循环核 1.循环核引入 2.循环核&#xff1a;循环核按时间步展开。 3.循环计算层&#xff1a;向输出方向生长。 4.TF描述循环计算层 三、TF描述循环计算 四、RNN使用案例 1.数据集准备 2.Sequential中RNN 3.存储模型&#xff0c;acc和lose…

MAC M2芯片执行yolov8 + deepsort 实现目标跟踪

MAC M2芯片执行yolov8 deepsort 实现目标跟踪 MAC M2 YoloX bytetrack实现目标跟踪 实验结果 MAC mps显存太小了跑不动 还是得用服务器跑 需要实验室的服务器跑 因为网上花钱跑4天太贵了&#xff01;&#xff01;&#xff01; 步骤过程尝试&#xff1a; 执行mot17 数据集 …

FSPI的PCB设计

FSPI是一种灵活的串行接口控制器&#xff0c;RK3588芯片中有1个FSPI控制器&#xff0c;可用来连接FSPI设备。 RK3588 FSPI 控制器有如下特点&#xff1a; 1&#xff09;支持串行NOR Flash&#xff0c;串行Nand Flash&#xff1b; 2&#xff09;支持SDR模式&#xff1b; 3&am…

Android屏幕显示 android:screenOrientation configChanges 处理配置变更 代码中动态切换横竖屏

显示相关 屏幕朝向 https://developer.android.com/reference/android/content/res/Configuration.html#orientation 具体区别如下&#xff1a; activity.getResources().getConfiguration().orientation获取的是当前设备的实际屏幕方向值&#xff0c;可以动态地根据设备的旋…

【STM32】学习笔记(EXTI)-江科大

EXTI外部中断 中断&#xff1a;在主程序运行过程中&#xff0c;出现了特定的中断触发条件&#xff08;中断源&#xff09;&#xff0c;使得CPU暂停当前正在运行的程序&#xff0c;转而去处理中断程序&#xff0c;处理完成后又返回原来被暂停的位置继续运行 中断优先级&#x…

【Python数据分析】数据分析之numpy基础

实验环境&#xff1a;建立在Python3的基础之上 numpy提供了一种数据类型&#xff0c;提供了数据分析的运算基础&#xff0c;安装方式 pip install numpy导入numpy到python项目 import numpy as np本文以案例的方式展示numpy的基本语法&#xff0c;没有介绍语法的细枝末节&am…

电商数仓项目需求及架构设计

一、项目需求 1.用户行为数据采集平台搭建 2.业务数据采集平台搭建 3.数仓维度建模 4.统计指标 5.即席查询工具&#xff0c;随时进行指标分析 6.对集群性能进行监控&#xff0c;发生异常时报警&#xff08;第三方信息&#xff09; 7.元数据管理 8.质量监控 9.权限管理&#xff…

streamlit-API

介绍 安装 pip install streamlit运行 streamlit run your_script.py [-- script args]数据流 多页应用程序 API 文本元素 数据元素 图标元素 输入小部件 媒体元素 布局和容器 聊天元素 st.chat_message st.chat_input 显示进度和状态 控制流 占位符/帮助/选项 图表改变 会…

SpringBoot工具类—基于定时器完成文件清理功能

直接复制粘贴既可&#xff01;&#xff01; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.io.File; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneOff…

云职达(上海)岗前实训基地(上海云职达):致力为企业提供良好的数字化解决方案

上海云职达全称&#xff1a;云职达上海信息科技有限公司&#xff0c;是一家致力于推动算力产业发展的企业。随着数字经济时代的到来&#xff0c;算力作为数字产业化和产业数字化转型的关键支撑&#xff0c;已经成为推进中国式现代化的重要驱动力量。云职达深入理解算力产业的重…

星辰天合荣获“2023年度优秀光伏行业数字化供应商”

8 月 28 日&#xff0c;由 OFweek 维科网及旗下权威的光伏专业媒体-维科网光伏共同举办的“OFweek 2023&#xff08;第十四届&#xff09;太阳能光伏产业大会暨光伏行业年度颁奖典礼”在深圳成功举办。 星辰天合凭借在光伏领域的优秀智能存储解决方案&#xff0c;以及大量的应用…

Rdedis 持久化

Redis 是内存数据库&#xff0c;如果不将内存中的数据库状态保存到磁盘&#xff0c;那么一旦服务器进程退出&#xff0c;服务器中的数据库状态也会消失。所以 Redis 提供了持久化功能&#xff01; 一、RDB&#xff08;Redis DataBase&#xff09; 1.1 概念 在指定的时间间隔内…