量化学习5(量化回测)

news2025/2/3 7:08:06

1 pandas计算策略评估指标

本章节介绍关于金融量化分析的一些基本概念,如年华收益率、基准年化收益率、最大回撤等。在严格的量化策略回测中,这些概念都是需要掌握并熟练使用的,这样能够全面的评估量化策略。市面上,很多策略回测笼统地使用所谓的“胜率”来确定策略的好坏,这是一种非常业余而且不可靠的分析方法。在衡量基金业绩好坏的时候,大部分人也只是看基金的年化收益,忽略了基金的风险情况(波动率)。市场中充斥着大量类似的业余的分析方法,这些方法导致很多所谓的回测看起来很美好,其实在统计上根本站不住脚,即所谓的“统计骗局”。 因此在量化回测过程中,需要从收益、稳定性、胜率、风险四个方面来综合评估策略好坏。熟练掌握评估指标,还能够帮助大家识别一些经典“骗局”,如

只展示基金的年化收益,而不提基金的波动率或者最大回撤或使用周收益率来计算夏普比率,而不是使用日收益率来计算

1.1 数据准备

为了帮助大家深入了解指标计算逻辑和实现方式,本章节采用指标讲解和代码实现相结合的方式进行讲解。再具体计算过程中,选择的目标标的是贵州茅台(600519.SH)、工商银行(601398.SH)、中国平安(601318.SH),策略基准是沪深300指数(000300.XSHG),策略采用最简单的方式:买入持有。持有周期为20180101 - 20221231,共1826个自然日。数据获取如下所示

import pandas as pd  
import numpy as np
import matplotlib.pyplot as plt
import tushare as ts
%matplotlib inline   

# 无视warning
import warnings
warnings.filterwarnings("ignore")

# 正常显示画图时出现的中文和负号
from pylab import mpl
mpl.rcParams['font.sans-serif']=['SimHei']
mpl.rcParams['axes.unicode_minus']=False

#起始和结束日期可以自行输入,否则使用默认
def get_data(code, start_date, end_date):
    # 配置 tushare token
    my_token = '***'  
    pro = ts.pro_api(my_token)

    df = pro.daily(ts_code=code, start_date=start_date, end_date=end_date)
    df.index = pd.to_datetime(df.trade_date)

    return df.close

#以上证综指、贵州茅台、工商银行、中国平安为例
stocks={
    '600519.SH':'贵州茅台',
    '601398.SH':'工商银行',
    '601318.SH':'中国平安'
}

df = pd.DataFrame()
for code,name in stocks.items():
    df[name] = get_data(code, '20180101', '20221231')

# 按照日期正序
df = df.sort_index()

# 本地读入沪深300合并
df_base = pd.read_csv('000300.XSHG_2018_2022.csv')
df_base.index = pd.to_datetime(df_base.trade_date)
df['沪深300'] = df_base['close']

000300.XSHG_2018_2022.csv 获取
在这里插入图片描述

1.2 净值曲线

净值曲线是一组时间序列的曲线,其含义表示为股票或基金在不同时间的价值相对于期初的价值的倍数。 再具体分析中,我们可以将期初价格定位1,那么如果你在当前时间点手里的净值是1.4,就意味着当前时间的资产价值是期初的1.4倍。

# 以第一交易日2018年1月1日收盘价为基点,计算净值并绘制净值曲线
df_worth = df / df.iloc[0]
df_worth.plot(figsize=(15,6))
plt.title('股价净值走势', fontsize=10)
plt.xticks(pd.date_range('20180101','20221231',freq='Y'),fontsize=10)
plt.show()

在这里插入图片描述

在这里插入图片描述

1.3 收益率指标

在这里插入图片描述

# 区间累计收益率(绝对收益率)
total_return = df_worth.iloc[-1]-1
total_return = pd.DataFrame(total_return.values,columns=['累计收益率'],index=total_return.index)
total_return

# 年化收益率
annual_return = pd.DataFrame((1 + total_return.values) ** (252 / 1826) - 1,columns=['年化收益率'],index=total_return.index)
annual_return

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

1.4 波动率指标

在这里插入图片描述

df_return = df / df.shift(1) - 1
df_return = ((df_return.iloc[1:] - df_return.mean()) ** 2)

volatility = pd.DataFrame(np.sqrt(df_return.sum() * 252 / (1826-1)),columns=['波动率'],index=total_return.index)
volatility

在这里插入图片描述

1.5 最大回撤

在这里插入图片描述

def max_drawdown_cal(df):
    md = ((df.cummax() - df)/df.cummax()).max()
    return round(md, 4)

max_drawdown = {}

stocks={
    '600519.SH':'贵州茅台',
    '601398.SH':'工商银行',
    '601318.SH':'中国平安',
    '000300.XSHG': '沪深300'
}

for code,name in stocks.items():
    max_drawdown[name]=max_drawdown_cal(df[name])

max_drawdown = pd.DataFrame(max_drawdown,index=['最大回撤']).T
max_drawdown

在这里插入图片描述

1.6 Alpha系数和Beta系数

在这里插入图片描述

from scipy import stats

#计算每日收益率 收盘价缺失值(停牌),使用前值代替
rets=(df.iloc[:,:4].fillna(method='pad')).apply(lambda x:x/x.shift(1)-1)[1:]

#市场指数为x,个股收益率为y
x = rets.iloc[:,3].values
y = rets.iloc[:,:3].values
capm = pd.DataFrame()
alpha = []
beta = []
for i in range(3):
    b, a, r_value, p_value, std_err=stats.linregress(x,y[:,i])
    #alpha转化为年化
    alpha.append(round(a*250,3))
    beta.append(round(b,3))
    
capm['alpha']=alpha
capm['beta']=beta
capm.index=rets.columns[:3]
#输出结果:
capm

在这里插入图片描述

在这里插入图片描述

1.7 夏普比率

在这里插入图片描述

# 超额收益率以无风险收益率为基准 假设无风险收益率为年化3%
ex_return=rets - 0.03/250

# 计算夏普比率
sharpe_ratio=np.sqrt(len(ex_return))*ex_return.mean()/ex_return.std()
sharpe_ratio=pd.DataFrame(sharpe_ratio,columns=['夏普比率'])
sharpe_ratio

在这里插入图片描述

1.8 信息比率

在这里插入图片描述

###信息比率
ex_return = pd.DataFrame() 
ex_return['贵州茅台']=rets.iloc[:,0]-rets.iloc[:,3]
ex_return['工商银行']=rets.iloc[:,1]-rets.iloc[:,3]
ex_return['中国平安']=rets.iloc[:,2]-rets.iloc[:,3]

#计算信息比率
information_ratio = np.sqrt(len(ex_return))*ex_return.mean()/ex_return.std()
#信息比率的输出结果
information_ratio = pd.DataFrame(information_ratio,columns=['信息比率'])
information_ratio

在这里插入图片描述

2 聚宽平台量化回测实践

2.1 平台介绍

聚宽(https://www.joinquant.com/) 成立于2015年5月,是一家量化交易平台,为投资者提供做量化交易的工具与服务,帮助投资者更好地做量化交易。 整体来看,聚宽具有以下几点优势

*聚宽让做量化交易的成本极大降低
*提供多种优质的便于取用的数据
*提供投资研究功能,便于自由地统计、研究、学习等
*提供多种的策略评价指标与评价维度
*支持多种策略的编写、回测、模拟、实盘
*具备丰富且活跃的量化社区,可以发帖、学习、比赛等。

2.2 策略实现

本部分将介绍如何在聚宽平台实现一个双均线策略(具体参照ch05择时策略),并且在聚宽平台上进行回测, 来测试整体收益率。

策略代码如下,核心点有:

*选择标的为:002594.XSHE 比亚迪
*选择基准为:000300.XSHG 沪深300
*策略为:当5日线金叉10日线,全仓买入;当5日线死叉10日线全仓卖出。

# 导入函数库
from __future__ import (absolute_import, division, print_function, unicode_literals) 
import datetime
import pymysql
import pandas as pd
import backtrader as bt
import tushare as ts
import numpy as np


# 数据获取(从Tushare中获取数据)
""" 
数据获取一般都是通过连接数据库从数据库中读取,对于不了解数据库来源的新手可以从Tushare中直接获取数据
"""
def get_data(stock_code):
    """
    stock_code:股票代码,类型: str
    return: 股票日线数据,类型: DataFrame
    """
    token = 'Tushare token'   # 可通过进入个人主页-接口TOKEN获得

    ts.set_token(token)
    pro = ts.pro_api(token)

    data_daily = pro.daily(ts_code = stock_code, start_date='20180101', end_date='20230101')
    data_daily['trade_date'] = pd.to_datetime(data_daily['trade_date'])
    data_daily = data_daily.rename(columns={'vol': 'volume'})
    data_daily.set_index('trade_date', inplace=True) 
    data_daily = data_daily.sort_index(ascending=True)
    dataframe = data_daily
    data_daily['openinterest'] = 0
    dataframe['openinterest'] = 0
    data = bt.feeds.PandasData(dataname=dataframe,
                               fromdate=datetime.datetime(2018, 1, 1),
                               todate=datetime.datetime(2023, 1, 1)
                               )

    return data


# 双均线策略实现
class DoubleAverages(bt.Strategy):

    # 设置均线周期
    params = (
        ('period_data5', 5),
        ('period_data10', 10)
    )

    # 日志输出
    def log(self, txt, dt=None):
        dt = dt or self.datas[0].datetime.date(0)
        print('%s, %s' % (dt.isoformat(), txt))

    def __init__(self):
        # 初始化数据参数

        self.dataclose = self.datas[0].close   # 定义变量dataclose,保存收盘价
        self.order = None   # 定义变量order,用于保存订单
        self.buycomm = None    # 定义变量buycomm,记录订单佣金
        self.buyprice = None    # 定义变量buyprice,记录订单价格

        self.sma5 = bt.indicators.SimpleMovingAverage(self.datas[0], period=self.params.period_data5)  # 计算5日均线
        self.sma10 = bt.indicators.SimpleMovingAverage(self.datas[0], period=self.params.period_data10)  # 计算10日均线

    def notify_order(self, order):
        if order.status in [order.Submitted, order.Accepted]:  # 若订单提交或者已经接受则返回
            return

        if order.status in [order.Completed]:
            if order.isbuy():
                self.log(
                    'Buy Executed, Price: %.2f, Cost: %.2f, Comm: %.2f' %
                    (order.executed.price, order.executed.value, order.executed.comm))

                self.buyprice = order.executed.price
                self.buycomm = order.executed.comm
            else:
                self.log('Sell Executed, Price: %.2f, Cost: %.2f, Comm: %.2f' %
                        (order.executed.price, order.executed.value, order.executed.comm))
            self.bar_executed = len(self)
        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log('Order Canceled/Margin/Rejected')

        self.order = None


    def notify_trade(self, trade):
        if not trade.isclosed:   # 若交易未关闭则返回
            return
        self.log('Operation Profit, Total_Profit %.2f, Net_Profit: %.2f' %
                (trade.pnl, trade.pnlcomm))    # pnl表示盈利, pnlcomm表示手续费

    def next(self):   # 双均线策略逻辑实现
        self.log('Close: %.2f' % self.dataclose[0])   # 打印收盘价格

        if self.order:   # 检查是否有订单发送
            return

        if not self.position:   # 检查是否有仓位
            if self.sma5[0] > self.sma10[0]:
                self.log('Buy: %.2f' % self.dataclose[0])
                self.order = self.buy()

        else:
            if self.sma5[0] < self.sma10[0]:
                self.log('Sell: %.2f' % self.dataclose[0])
                self.order = self.sell()





if __name__ == '__main__':
    cerebro = bt.Cerebro()   # 创建策略容器
    cerebro.addstrategy(DoubleAverages)    # 添加双均线策略
    data = get_data('000001.SZ')
    cerebro.adddata(data)   # 添加数据
    cerebro.broker.setcash(10000.0)   # 设置资金
    cerebro.addsizer(bt.sizers.FixedSize, stake=100)   # 设置每笔交易的股票数量
    cerebro.broker.setcommission(commission=0.01)   # 设置手续费
    print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())   # 打印初始资金
    cerebro.run()   # 运行策略
    print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())   # 打印最终资金
    cerebro.plot()

)

在这里插入图片描述

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

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

相关文章

C++游戏开发的优势

C作为一种高效的编程语言&#xff0c;在游戏开发领域有着独特的优势。通过充分利用C的特性&#xff0c;游戏开发人员可以实现更高的性能、可移植性和灵活性。下面简单的介绍C游戏开发的优势&#xff0c;并探讨它在游戏开发中的应用。 性能优势 游戏是对计算机系统资源要求很高…

深入理解指针(2)

⽬录 1. 字符指针变量 2. 数组指针变量 3. ⼆维数组传参的本质 4. 函数指针变量 5. 函数指针数组 6. 转移表 1. 字符指针变量 在指针的类型中我们知道有⼀种指针类型为字符指针 char* ; ⼀般使⽤: int main() {char ch w;char *pc &ch;*pc w;return 0; } 还有…

雨云游戏云VPS服务器用Linux搭建MCSM面板和Minecraft Mohist 1.20.2服务器教程,我的世界MOD和插件服开服教程。

雨云游戏云VPS服务器用Linux搭建MCSM面板和Minecraft Mohist 1.20.2服务器教程&#xff0c;我的世界MOD和插件服开服教程。 本教程演示安装的MC服是Mohist 1.20.2版&#xff0c;其他版本也可以参考本教程&#xff0c;差别不大。 本教程使用Docker来运行mc服&#xff0c;可以方…

51单片机编程应用(C语言):模块化编程

下面我们模块化几个函数&#xff1a; Delay.c //延时子函数 void Delay(unsigned int xms) {unsigned char i, j;while(xms--){i 2;j 239;do{while (--j);} while (--i);} } Delay.h #ifndef __DELAY_H__ #define __DELAY_H__void Delay(unsigned int xms);#endifNixie.h …

ElasticSearch搜索与分析引擎-Linux离线环境安装教程

目录 一、下载安装包 网盘链接: 二、安装流程及遇到的问题和解决方案 &#xff08;1&#xff09;JDK安装 &#xff08;2&#xff09;Elasticsearch安装 &#xff08;3&#xff09;Kibana安装 ​&#xff08;4&#xff09;Ik分词器安装 三、启动过程中的问题 &#xff…

接口自动化处理动态参数

接口自动化处理动态参数 1、流程说明 某些接口的请求入参数据不能写死&#xff0c;需要动态传参。如用户注册接口&#xff0c;用户名需要动态生成。使用yaml编写测试数据时&#xff0c;在需要动态参数的数据后面添加上特殊字符${生成动态数据的方法名&#xff08;参数&#x…

Find My点读笔|苹果Find My技术与点读笔结合,智能防丢,全球定位

点读笔是采用国际最新光学图像识别技术和先进的数码语音技术开发而成的新一代智能阅读和学习工具。它体现了电子产品与教育行业的完美融合&#xff0c;实现了科技以人为本的理念。点读笔能同时实现点读、复读、跟读、录音、娱乐等诸多功能。由于小孩贪玩很容易造成点读笔的丢失…

基于OpenCV灰度图像转GCode的单向扫描实现

基于OpenCV灰度图像转GCode的单向扫描实现 引言单向扫描存在的问题灰度图像单向扫描代码示例结论 基于OpenCV灰度图像转GCode的单向扫描实现 本文将介绍如何使用OpenCV库将灰度图转换为GCode&#xff0c;并通过单向扫描实现对图像的激光雕刻。GCode是一种用于控制数控机床和…

物联网自动虫情测报仪器

TH-CQ3S在农业生产的进程中&#xff0c;病虫害的防治始终是关键的一环。然而&#xff0c;传统的病虫害监测手段往往存在着效率低下、准确度不高等问题&#xff0c;这无疑给农业生产带来了巨大的困扰。好在&#xff0c;随着科技的飞速发展&#xff0c;一款基于物联网技术的自动虫…

Oracle闪回日志管理(flashbackup log)

Oracle闪回日志管理&#xff08;flashbackup log&#xff09; 1.开启闪回日志 shutdown immediate startup mount; alter database archivelog; alter database flashback on; alter database open; 2、查看闪回日志保留期限 show parameter flash 默认是1440分钟&#xff0c…

【软件设计师笔记】程序语言设计考点

【考证须知】IT行业高含金量的证书(传送门)&#x1f496; 【软件设计师笔记】计算机系统基础知识考点(传送门)&#x1f496; 【软件设计师笔记】操作系统考点(传送门)&#x1f496; &#x1f413; 编程语言之间的翻译形式 汇编 高级程序不能直接在计算机上执行&#xff0c;…

极狐GitLab 和飞书的集成实践

飞书集成和通知 如果您想在飞书的群组中查看极狐GitLab 项目中的事件变更&#xff0c;如创建议题、流水线故障或关闭合并请求等&#xff0c;您可以将飞书与极狐GitLab 进行集成。 飞书集成 配置飞书 在飞书中创建机器人在飞书群组中添加机器人 在飞书中创建机器人&#xff…

【全网最全】2024美赛ABCDEF题思路模型全解(后续会更新)

欲获取更多资料&#xff0c;一定要点击这里并关注文末的公众号&#xff01;&#xff01;&#xff01; 最新更新&#xff1a;我们团队不仅在第一时间更新了24美赛全题目的深度翻译和深入分析&#xff0c;经过爆肝奋战&#xff0c;我们在第一时间给出了ABCDEF全题目的完整建模过程…

OSPF——开放最短路径优先、多区域OSPF

目录 1 内部网关协议 OSPF 1.1 三个主要特点&#xff08;生成拓扑图) 其他特点 1.2 链路状态数据库 (link-state database) 1.3 链路状态路由过程 1.4 OSPF 的五种分组类型 1.4.1 OSPF 分组用 IP 数据报传送 1.5 OSPF 工作过程 1.6 OSPF 定义五种网络类型 1.7 多路访…

WAF 无法防护的八种风险

一、目录遍历漏洞 测试用例&#xff1a;Apache 目录遍历漏洞 测试环境搭建&#xff1a; apt intsall apache2 && cd /var/www/html/ && rm index.html无法拦截原因&#xff1a; 请求中无明显恶意特征&#xff0c;无法判断为攻击行为 实战数据&#xff1a; 截…

飞腾D2000+X100的UART串口调试方法

一、测试使用主板的串口说明 D2000自带的UART0直接引出9针全功能RS232串口,UART1为CPU调试串口,UART2和UART3接485接口芯片转为RS485,此外,主板还有X100 usb2.0转出8路RS232,详细硬件框图如下: 源芯片串口号串口电平连接器丝印D2000UART0RS232COM0D2000UART1TTL调试串口…

LightDB24.1 存储过程中声明的不带参数的游标,支持open 游标名加括号的调用方式

背景 oracle 存储过程中不带参数声明的游标&#xff0c;可以在open打开时加上括号进行调用。在老的业务中经常能够看到这种用法。虽然觉得不合理&#xff0c;但是oracle人家支持&#xff0c;作为兼容性极强的LightDB不会在这个小水沟翻车的&#xff0c;果断进行支持一波。 L…

【鸿蒙千帆起】高德地图携手 HarmonyOS NEXT,开启智能出行新篇章

2024 年 1 月 18 日下午&#xff0c;华为举办了鸿蒙生态千帆启航仪式&#xff0c;对外宣布 HarmonyOS NEXT 星河预览版现已开放申请&#xff0c;同时&#xff0c;首批 200鸿蒙原生应用加速开发&#xff0c;鸿蒙生态设备数量更是突破了 8 亿大关。这些进展反映了开发者和合作伙伴…

Jmeter+ant+Jenkins 接口自动化框架完整版

接口自动化测试单有脚本是不够的&#xff0c;我们还需要批量跑指定接口&#xff0c;生成接口运行报告&#xff0c;定位报错接口&#xff0c;接口定时任务&#xff0c;邮件通知等功能。批量跑指定接口&#xff1a;我们可以利用ant批量跑指定目录下的Jmeter脚本生成接口运行报告&…

上传upload及显示img图片预览、删除

上传图片文件a-upload html部分 <div className="clearfix"><a-upload:custom-request="customRequest"listType="picture-card":fileList="fileList":onPreview="handlePreview":on-remove="del">&…