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时,性能较差。

相关文章:
Python股票交易---均值回归
免责声明:本文提供的信息仅用于教育目的,不应被视为专业投资建议。在做出投资决策时进行自己的研究并谨慎行事非常重要。投资涉及风险,您做出的任何投资决定完全由您自己负责。 在本文中,您将了解什么是均值回归交易算法ÿ…...
机器人制作开源方案 | 桌面级机械臂--本体说明+驱动及控制
一、本体说明 1. 机械臂整体描述 该桌面级机械臂为模块化设计,包含主机模块1个、转台模块1个、二级摆动模块1个、可编程示教盒1个、2种末端执行器、高清摄像头,以及适配器、组装工具、备用零件等。可将模块快速组合为一个带被动关节的串联3自由度机械臂…...
有哪些前端调试和测试工具? - 易智编译EaseEditing
前端开发调试和测试工具帮助开发人员在开发过程中发现和修复问题,确保网站或应用的稳定性和性能。以下是一些常用的前端调试和测试工具: 调试工具: 浏览器开发者工具: 现代浏览器(如Chrome、Firefox、Safari等&#…...
【数据结构】手撕单链表
目录 一,链表的概念及结构 二,接口实现 1,单链表的创建 2,接口函数 3,动态创立新结点 4,打印 5,头插 6,头删 7,尾插 8,尾删 9,查找 10ÿ…...
两个git本地如何配置两个ssh密钥for mac
我是在mac上操作的。windows上也差不多一样操作。 1.找到本地的.ssh文件。我的文件结构如下如: 文件结构: (1)两个known_hosts文件是自动生成的,不用管 (2)readme文件是我个人记事本记录笔记…...
iOS逆向进阶:iOS进程间通信方案深入探究与local socket介绍
在移动应用开发中,进程间通信(Inter-Process Communication,IPC)是一项至关重要的技术,用于不同应用之间的协作和数据共享。在iOS生态系统中,进程和线程是基本的概念,而进程间通信方案则为应用的…...
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…...
针对java中list.parallelStream()的多线程数据安全问题我们采用什么方法最好呢?
当使用List.parallelStream()方法进行多线程处理时,可能会涉及到数据安全问题。下面是一些常见的方法来处理parallelStream()的多线程数据安全问题: 1. 使用线程安全的集合:Java中提供了线程安全的集合类,如CopyOnWriteArrayList…...
校园用电安全管理系统可以识别违规电器吗
校园用电安全管理系统是处理恶意用电问题有效手段之一,系统具有实时监测、异常预警、监测设备运行状态、远程控制用电等功能,可以从根本上管理学校用电量,制定合理的用电计划,限制用电成本,避免各种恶意用电行为&#…...
前端(十五)——开源一个用react封装的图片预览组件
👵博主:小猫娃来啦 👵文章核心:开源一个react封装的图片预览组件 文章目录 组件开源代码下载地址运行效果展示实现思路使用思路和api实现的功能数据和入口部分代码展示 组件开源代码下载地址 Gitee:点此跳转下载 CSDN…...
idea新建Java-maven项目时,出现Dependency ‘ xxx(jar包名)‘ not found的解决方案
项目场景: 项目场景:使用idea创建maven项目时,导入简单依赖时(本文以mysql-connector-java为例)。 问题描述 问题: 首先,在创建新的maven项目中,出现下列两种情况: &am…...
C# 获取Windows系统版本注意事项
首先通过微软官方文档:https://learn.microsoft.com/zh-cn/windows/win32/sysinfo/operating-system-version了解各个操作系统对应的版本号 下面介绍3种获取版本号的方式及弊端 1. Environment.OSVersion.Version OperatingSystem os Environment.OSVersion;// 判断…...
STM32设计的宠物投喂器(正点原子mini开发板+2.8寸屏)
一、设计需求 【1】 项目背景 在竞争日益激烈的今天,各行各业为提高竞争力,纷纷推出了各种新、奇的事物来吸引消费者。经过长时间的市场调查,发现广大市民及民营企业家大多还采用传统的人工喂养方式,这种方式不但耗费了大量的人力资源,而且由于现在的人力成本的不断增加…...
Python编程——深入了解不可变的元组
作者:Insist-- 个人主页:insist--个人主页 本文专栏:Python专栏 专栏介绍:本专栏为免费专栏,并且会持续更新python基础知识,欢迎各位订阅关注。 目录 一、元组是什么 二、元组的定义 1、相同类型组成元组…...
JVM——类加载与字节码技术—类加载器+运行期优化
5.类加载器 jdk的类加载器具有层级关系。 启动类加载器》扩展类加载器》应用程序类加载器》自定义类加载器 对应类加载器只会负责加载对应目录的类。 双亲委派上级机制 应用程序类加载器加载一个类之前会先查询上级加载器是否已经加载过了该类。然后再让上级询问上上级。都…...
[linux实战] 华为云耀云服务器L实例 Java、node环境配置
系列文章目录 第一章 [linux实战] 华为云耀云服务器L实例 Java、node环境配置 文章目录 系列文章目录前言一、任务拆解二、修改密码三、配置安全规则四、远程登录并更新apt五、安装、配置JDK环境5.1、安装openjdk,选择8版本5.2、检查jdk配置 六、安装、配置git6.1、安装git6.2…...
python面试:使用cProfile剖析程序性能
我们需要安装tuna:pip install tuna 程序执行完毕后,我们会得到一个results.prof,在CMD中输入指令:“tuna results.prof”。 import time import cProfile import pstatsdef add(x, y):resulting_sum 0resulting_sum xresulti…...
leetcode-188-买卖股票的最佳时机 IV
1. 问题描述 https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iv/description/ 2. 解题代码 public class Solution {public int MaxProfit(int k, int[] prices) {if(prices.Length<2){return 0;}if(k0){return 0;}List<int> listValuenew List<…...
Grounded Language-Image Pre-training论文笔记
Title:Grounded Language-Image Pre-training Code 文章目录 1. 背景2. 方法(1)Unified Formulation传统目标检测grounding目标检测 (2)Language-Aware Deep Fusion(3)Pre-training with Scala…...
成集云 | 钉钉财务费用单同步至畅捷通 | 解决方案
源系统成集云目标系统 方案介绍 财务管理作为企业管理中重要的组成部分,在企业的发展和成长中扮演着重要角色,成集云以钉钉费用单OA审批与畅捷通TCloud系统为例,与钉钉连接器深度融合,通过数据处理和字段匹配实现了费用…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
spring Security对RBAC及其ABAC的支持使用
RBAC (基于角色的访问控制) RBAC (Role-Based Access Control) 是 Spring Security 中最常用的权限模型,它将权限分配给角色,再将角色分配给用户。 RBAC 核心实现 1. 数据库设计 users roles permissions ------- ------…...
若依登录用户名和密码加密
/*** 获取公钥:前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...
MySQL体系架构解析(三):MySQL目录与启动配置全解析
MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录,这个目录下存放着许多可执行文件。与其他系统的可执行文件类似,这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中,用…...
Django RBAC项目后端实战 - 03 DRF权限控制实现
项目背景 在上一篇文章中,我们完成了JWT认证系统的集成。本篇文章将实现基于Redis的RBAC权限控制系统,为系统提供细粒度的权限控制。 开发目标 实现基于Redis的权限缓存机制开发DRF权限控制类实现权限管理API配置权限白名单 前置配置 在开始开发权限…...
