量化交易backtrader实践(二)_基础加强篇(1)_数据列表准备与主要实践内容

news2024/12/23 4:55:59

上一篇回顾

上一篇是数据获取篇,在上一篇里,我们初步接触了backtrader的回测逻辑,重点放在了回测的数据获取的问题上,确保了我们在用合适且有效的正规数据在做回测,我们的目的是要通过backtrader深入讨论量化交易的内容,并在实践中逐步完善自己的交易系统和养成正确的交易思路。

  1. 第1节里讨论了backtrader的数据来源,对pandas的数据要求进行了分析,做到能把相应的数据处理成backtrader接受的格式。
  2. 第2节里通过akshare获取了全股票列表/ETF列表,使用pypinyin库制作了中文名/拼音缩写/代码都能查找的功能,制作了自选股列表并且通过akshare获取了日线的历史行情数据。
  3. 第3节爬取数据是支线拓展与主线任务关系不太。
  4. 第4节结合通达信的应用,为backtrader更深入、多样化应用提供了新的思路。

那么,我们会以数据获取篇为基础,继续我们的backtrader实践。

基础回测加强

01_数据及列表准备

从第一篇已经知道怎样获取用于回测的数据,但单一的数据没有代表性,这里先准备5支股票+2个指数用于后续的实践,并且直接制作函数通过akshare下载并处理数据,存放在df_list中,对于Notebook而言,它的workspace会保存我们在操作过程中的变量,数据和函数,让我们可以在其他格子里代码调用它们。

001_选股

一般在股票软件中都是选股的功能,不同的软件都有其各自的特色。而且现在又出来AI选股的功能,比如通达信的小达,同花顺的问财等。

选股是交易的前置条件,如果选中了一支接下来趋势向上的股票,那么多半最终收益是正的,而你应用的策略胜率和盈亏比都会比较高,否则就是相反,多半是亏损的。

以小达为例,我们可以通过”热点“,”主题“,“板块” 及“热搜” 针对当前的热点及进选股,也可以根据基本面(市盈率,市净率...)或者资金面,或者K线形态(红三兵,出水芙蓉...)以及技术指标策略(MACD金叉死叉...)进行选股操作。

后续我们的策略也会参考着对指标,基本面以及热度进行回测。不过当前,我们需要从5000多支股票中选出5支股票。这里我们采用akshare读取股票热度排名,然后以第500名开始每隔1000名选择一个。

# 获取问财最近交易日的热度排名

import akshare as ak

stock_hot_rank_wc_df = ak.stock_hot_rank_wc(date="20240913")
stock_hot_rank_wc_df

-----------------------
	序号	股票代码	股票简称	现价	涨跌幅	个股热度	个股热度排名	排名日期
0	    1	000536	华映科技	3.63	10.00	30762469.0	1/5359	20240913
1	    2	600611	大众交通	6.76	-9.99	27546732.5	2/5359	20240913
2	    3	000062	深圳华强	29.48	-9.98	27264696.5	3/5359	20240913
3	    4	000158	常山北明	8.30	-4.16	23935850.0	4/5359	20240913
4	    5	600550	保变电气	8.51	9.95	17938728.5	5/5359	20240913
...	...	...	...	...	...	...	...	...
4995	4996	688100	威胜信息	34.31	-0.70	14574.0	4996/5359	20240913
4996	4997	688432	有研硅	8.75	-0.79	14512.5	4997/5359	20240913
4997	4998	600051	宁波联合	5.20	-0.76	14504.0	4998/5359	20240913
4998	4999	688130	晶华微	16.60	-2.24	14503.5	4999/5359	20240913
4999	5000	002200	ST交投	4.86	-0.20	14477.5	5000/5359	20240913
5000 rows × 8 columns

 获取5支股票,使用pandas的列表索引功能获取这5支股票的信息如下:

sel_index = [500,1500,2500,3500,4500]
df_sel = stock_hot_rank_wc_df.iloc[sel_index,:]
df_sel

-----------------------------
	    序号	股票代码	股票简称	现价	涨跌幅	个股热度	个股热度排名	排名日期
500	    501	    001287	中电港	15.51	-2.76	537239.5	501/5359	20240913
1500	1501	002179	中航光电	36.95	-2.28	169509.0	1501/5359	20240913
2500	2501	600860	京城股份	7.53	-1.57	89909.0	2501/5359	20240913
3500	3501	300233	金城医药	10.99	-0.81	50961.5	3501/5359	20240913
4500	4501	002774	快意电梯	5.39	-1.46	26007.5	4501/5359	20240913

通过pandas的tolist()把选中的股票代码列(Series类型)转成列表,得到我们的自选股列表:

myStockList = df_sel.股票代码.tolist()
myStockList 

---------------------
['001287','002179','600860','300233','002774']

002_选指数

除了5支股票外,我们还需要选择2个指数,用于基准。在后续的“评价”里会详细说关于基准日收益的问题,现在只需要知道我们要一个上证指数,一个沪深300指数作为回测股票的对比基准即可。

指数有很多,在通达信里打开市场--主要指数的页面,就会把沪深京的主要指数列出来,从这里我们先记录下这些指数的代码:

  • 上证指数: 000001 (这个就是sh000001,深市的平安银行也是000001(sz000001?))
  • 沪深300指数: 000300
  • 深证成指:399001
  • 创业板指:399006
  • 5年国债指数:000140

仍然可以采用akshare来获取指数的历史行情数据,函数从stock开头换成index开头:

df_index_em = ak.index_zh_a_hist('000300',start_date='20220101')
df_index_em

------------------------
	日期	开盘	收盘	最高	最低	成交量	成交额	振幅	涨跌幅	涨跌额	换手率
0	2022-01-04	4957.98	4917.77	4961.45	4874.53	151534776	3.365170e+11	1.76	-0.46	-22.60	0.48
1	2022-01-05	4907.93	4868.12	4916.28	4851.98	178816100	3.639445e+11	1.31	-1.01	-49.65	0.57
2	2022-01-06	4842.16	4818.23	4857.56	4786.43	157665825	3.217501e+11	1.46	-1.02	-49.89	0.50
3	2022-01-07	4824.32	4822.37	4856.65	4818.19	187139412	3.322189e+11	0.80	0.09	4.14	0.60
4	2022-01-10	4812.23	4844.05	4844.39	4780.82	156211697	3.050338e+11	1.32	0.45	21.68	0.50
...	...	...	...	...	...	...	...	...	...	...	...
651	2024-09-09	3214.80	3192.95	3222.93	3180.93	108673069	1.465161e+11	1.30	-1.19	-38.40	0.35
652	2024-09-10	3193.46	3195.76	3205.10	3171.79	97290078	1.336105e+11	1.04	0.09	2.81	0.31
653	2024-09-11	3187.05	3186.13	3197.34	3174.03	102482110	1.415138e+11	0.73	-0.30	-9.63	0.33
654	2024-09-12	3189.43	3172.47	3201.55	3171.88	92868657	1.363872e+11	0.93	-0.43	-13.66	0.30
655	2024-09-13	3174.03	3159.25	3188.91	3159.25	88336677	1.374489e+11	0.93	-0.42	-13.22	0.28
656 rows × 11 column

003_用宽指ETF代替指数

简单的说,就是可以用ETF在某些情况下代替指数,且ETF是可以交易的。我们可以首先获取到ETF的实时行情,并只取代码,名称和前几列的数据:

import akshare as ak
import pandas as pd

fund_etf_spot_em_df = ak.fund_etf_spot_em()
df_etf = fund_etf_spot_em_df.iloc[:,:5]

---------------------
	代码	名称	最新价	IOPV实时估值	基金折价率
0	159321	黄金股票ETF	0.834	0.8272	-0.82
1	159315	黄金股ETF基金	0.873	0.8695	-0.40
2	159562	黄金股ETF	1.141	1.1395	-0.13
3	517400	黄金股票ETF	0.846	0.8452	-0.09
4	517520	黄金股ETF	1.050	1.0508	0.08
...	...	...	...	...	...
951	159327	半导体设备ETF基金	0.856	0.8583	0.27
952	159775	新能源车电池ETF	0.423	0.4233	0.07
953	517880	品牌消费ETF	0.727	0.7256	-0.19
954	515030	新能源车ETF	0.909	0.9110	0.22
955	588830	科创新能源ETF	0.919	0.9221	0.34
956 rows × 5 columns

然后使用Pandas的DataFrame进行查询,得到含有“沪深300”的项或者含有“上证”的项

df_hs300 = df_etf.loc[df_etf['名称'].str.contains('沪深300'),:]
df_hs300.head(10)

---------------------
	代码	名称	最新价	IOPV实时估值	基金折价率
181	560330	沪深300价值ETF申万菱信	0.959	0.9586	-0.04
270	562320	沪深300价值ETF	1.028	1.0294	0.14
275	159330	沪深300ETF基金	0.951	0.9490	-0.21
284	159510	沪深300价值ETF	0.898	0.8968	-0.13
301	561900	沪深300ESGETF	0.678	0.6776	-0.06
342	512530	沪深300红利ETF	1.251	1.2506	-0.03
388	515360	方正沪深300ETF	4.273	4.2649	-0.19
394	515390	沪深300ETF指数基金	0.894	0.8937	-0.03
395	561000	沪深300ETF增强基金	0.892	0.8929	0.10
406	159673	沪深300ETF鹏华	0.845	0.8434	-0.19

比如这里我们就选择515390这支ETF做沪深300指数的替代数据。

004_数据与列表保存

myStockList = ['001287','002179','600860','300233','002774']
myIndexList = ['000001','000300']

df_stock_list = []   # 用于保存每支股票的dataframe数据
df_index_list = []

def get_df_from_stock(code1):
    stock_df = ak.stock_zh_a_hist(symbol=code1, period="daily", start_date="20210301", adjust="qfq")
    stock_df.rename(columns={
        '日期':'date','开盘':'open','收盘':'close',
        '最高':'high','最低':'low', '成交量':'volume',
    },inplace=True)

    stock_df.index = pd.to_datetime(stock_df.date)
    stock_df['openinterest'] = 0
    stock_df = stock_df[['open','high','low','close','volume','openinterest']]
    return stock_df

def get_df_from_index(code1): # 与上面函数只是请求函数名不同index_zh_a_hist
    pass  # 略

for x in myIndexList:
    df_tmp = get_df_from_index(x)
    df_index_list.append(df_tmp)

for x in myStockList:
    df_tmp = get_df_from_stock(x)
    df_stock_list.append(df_tmp)

到这里,我们就把后续回测要用到的5支股票和2支指数的数据准备好了。

02_最简回测系统及问题

001_生成最简回测代码

我们还是通过AI助手生成backtrader双均线策略的回测代码,这里的代码就相当于一个最简回测系统。然后在上面把我们的数据放进去,这次用的是myStockList[2],即“600860-京城股份”的数据,开始日期为2021/9/1,结束日期默认当前最后一个交易日,跨度差不多为3年。

from datetime import datetime
import backtrader as bt

class SmaCross(bt.Strategy):
    params = (
        ('fast', 5),
        ('slow', 10),
    )

    def __init__(self):
        self.fast_ma = bt.indicators.SMA(self.data.close, period=self.params.fast)
        self.slow_ma = bt.indicators.SMA(self.data.close, period=self.params.slow)

        self.crossover = bt.indicators.CrossOver(self.fast_ma, self.slow_ma)

    def next(self):
        if not self.position:
            if self.crossover > 0:
                self.buy() 
        else:
            if self.crossover < 0:
                self.close()

cerebro = bt.Cerebro()                           # 创建Cerebro引擎
# 将数据源设置为PandasData,并加载数据
data = bt.feeds.PandasData(dataname=df_stock_list[2],fromdate=datetime(2021, 9, 1))
cerebro.adddata(data)                           # 将数据添加到Cerebro

cerebro.addstrategy(SmaCross)                   # 添加策略

cerebro.broker.setcash(100000.0)                # 设置初始资金
cerebro.broker.setcommission(commission=0.001)  # 设置交易佣金
cerebro.addsizer(bt.sizers.PercentSizer, percents=50) # 设置每次交易使用资金的比例为50%
print(f'Start Portfolio Value: {cerebro.broker.getvalue():.2f}')  # 打印起始组合价值

cerebro.run()  # 运行分析

print(f'Final Portfolio Value: {cerebro.broker.getvalue():.2f}')    # 打印最后组合价值
cerebro.plot()    # 绘制结果图 

----------------------------
Start Portfolio Value: 100000.00
Final Portfolio Value: 138102.81

从结果上看这次回测是盈利的,而且利润率达到惊人的38%,但从图形输出上看,恰好开局在低位不到7块,然后拉升到了25之上,如果回测的时间点往后2个月(2021/11/1)再开始,那么从高位掉到最后的7.53,最终的资产是 67172.88,反而亏了30%多。所以,单一的时间跨度可以有很大的概率出现妖的情况,并不代表策略的整体水平,这也是评价指标里大多会有近半年,近1年,近2年收益的指标,从而更多方位,较全面的策略进行分析。策略是需要择时的。

002_最简回测的问题

由于上面只是一个最简的回测系统,只是刚刚能把一个策略跑起来,因此它必然存在很多的疑问和问题,我们要一个一个的来看,并通过实践理解、解决或改善它们。

我们从代码顺序和显示图像的从上至下的顺序来看一下:

  1. bt.feeds.PandasData() - 把准备好的股票DataFrame数据转换成backtrader的格式,涉及到起止日期的选择,datetime类型的应用,另外如果对多支股票(我们已经准备好了5支股票)进行回测如何变化等。
  2. adddata(data) - 可以添加多个data吗?多个data数据怎么获取和处理?
  3. addstrategy() - 策略类怎么写,可以添加多个strtegy吗?几个data能用同一个策略吗?
  4. broker.setcash , setcommission - 怎么设置资金、佣金、滑点...与交易相关的数值
  5. cerebro.plot() - 绘制图形,(观察器 observer)
    • 图的第一栏是资产和现金变化曲线,一开始就冲到240000去了,后面全是在回撤
    • 所以有没有显示回撤的曲线,需要添加
    • 交易的成功/失败图标和颜色不易于观察,需要修改
    • 主图上没有K线,默认是收盘close的连线,需要修改
    • 主图上buy/sell的图标与颜色是国际的涨绿跌红,与我们国情相反,需要修改
    • 主图上的volume柱状图的颜色也反了,也需要修改
    • 哪些指标在主图上显示,哪些在副图上?怎么设置?

03_后续主要实践内容与目标

001_后续实践内容

由上面最简回测系统初步观察到的问题,我们把本篇后续的实践内容制定了初步的计划:

  • 数据(data)进阶 - 包括feeds多个股票数据,adddata多个data,这些数据怎么获取和应用
  • 策略(strategy)进阶 - strategy类包含哪些,多策略循环
  • 交易设置(broker)进阶 - 各种交易的设置,建立自己的交易体系
  • 观察器与绘图进阶 - 绘制符合我们需要的图形

002_本篇的目标

通过完成本篇的基础加强的实践后,我们可以把所有的更改和添加的数据、类、函数等都制作到一个xx.py文件,这样后续在notebook里%run xx.py文件就能把增强的配置load进Notebook中,每次新的回测只需要写策略类的核心代码即可,就能完成股票的回测,且能够循环回测。

在完成本篇实践后,对交易系统有更深层的理解,并能把策略的研究作为重点,可以忽略其他一些繁琐的小问题,把时间和精力集中放在策略的编写和优化上,能大大提升我们的效率。


 

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

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

相关文章

【Linux进程控制】进程等待

目录 进程等待 进程等待是什么&#xff1f; 为什么&#xff1f; 怎么办&#xff1f; wait方法 获取子进程status 多进程的等待问题 waitpid方法 什么是阻塞等待&#xff1f;什么是非阻塞等待&#xff1f; wait/waitpid获取子进程信息原理 进程等待 进程等待是什么&am…

【AI学习】陶哲轩在 2024 年第 65 届国际数学奥林匹克(IMO)的演讲:AI 与数学

陶哲轩在 2024 年第 65 届国际数学奥林匹克关于AI 和数学的演讲&#xff0c;很有意思。陶哲轩的讲话语速太快了&#xff0c;足见其聪明&#xff01; AI用于数学的一些方面&#xff1a; 陶哲轩介绍到刚刚被数学家接受并开始普及的方法&#xff1a;形式化证明辅助工具。 形式化…

API:连接数字世界的隐形纽带

在这个智能手机和应用程序无处不在的时代&#xff0c;你可能听说过API这个术语&#xff0c;但你知道它究竟是什么吗&#xff1f;API&#xff0c;全称为应用程序编程接口&#xff08;Application Programming Interface&#xff09;&#xff0c;是一种让不同的软件和服务之间能够…

MySQL基础篇(黑马程序员2022-01-18)

1 MySQL数据库概述 1.1 MySQL数据库的下载,安装,启动停止 1.2 数据模型 (1)关系型数据库(RDBMS) 概念&#xff1a;建立在关系模型基础上&#xff0c;由多张相互连接的二维表组成的数据库。 特点&#xff1a; A. 使用表存储数据&#xff0c;格式统一&#xff0c;便于维护。…

C++11第五弹:线程库 | 互斥锁 | 原子操作

&#x1f308;个人主页&#xff1a; 南桥几晴秋 &#x1f308;C专栏&#xff1a; 南桥谈C &#x1f308;C语言专栏&#xff1a; C语言学习系列 &#x1f308;Linux学习专栏&#xff1a; 南桥谈Linux &#x1f308;数据结构学习专栏&#xff1a; 数据结构杂谈 &#x1f308;数据…

蓝牙耳机是入耳式的好还是开放式的好?2024开放式耳机推荐

个人推荐入开放式耳机&#xff0c;戴起来更舒服&#xff0c;主要有以下几方面原因&#xff1a; 减少对耳部的压迫&#xff1a; 不入耳设计&#xff1a;开放式耳机通常不需要插入耳道&#xff0c;避免了对耳道的直接压迫。入耳式耳机的耳塞长时间塞在耳道内&#xff0c;会对耳…

Linux基础---07文件传输

Linux文件传输地图如下&#xff0c;先选取你所需的场景&#xff0c;若你是需要Linux和Linux之间传输文件就查看SCP工具即可。 一.下载网站文件 前提是有网&#xff1a; 检查网络是否畅通命令&#xff1a;ping www.baidu.com&#xff0c;若有持续的返回值就说明网络畅通。Ctr…

前端基础知识(HTML+CSS+JavaScript)

文章目录 一、HTML1.1 HTML 基础&#xff1a;1.1.1 HTML 的概念&#xff1a;1.1.2 认识 HTML 标签&#xff1a;1.1.3 HTML 文件基本结构&#xff1a;1.1.4 标签层次结构&#xff1a; 1.2 HTML 快速入门&#xff1a;1.3 HTML常见标签&#xff1a;1.3.1 标题标签&#xff1a;h1-h…

数据结构-2.顺序表

1.线性表 线性是n个具有相同特性的数据元素的有限序列. 线性表是一种在实际中广泛使用的数据结构,常见的线性表有: 顺序表 , 链表 , 栈 , 队列... 线性表在逻辑上是线性结构, 也就是连续的一条直线 . 但是在物理结构上并不是连续的, 线性表在物理上存储时, 通常以数组和链式结…

5-----RYZ维修工具 操作界面预览与功能操作解析 刷机 解锁 修复参数等等

以上是工具选项功能的界面预览 。通过预览可以看到很多功能选项。此类工具涵盖了很多操作区域。需要根据自己机型的实际需求来操作。根据开发者的描述。此工具有一下功能。包含mtk刷机 分区修复。9008刷机 备份基带efs等等。 高通操作区域 高通修复串码 高通修改写入基带qc…

石化盈科PMO总经理任志婷受邀为第四届中国项目经理大会演讲嘉宾

全国项目经理专业人士年度盛会 石化盈科信息技术有限责任公司运营管理部总经理兼PMO总经理任志婷女士受邀为PMO评论主办的全国项目经理专业人士年度盛会——2024第四届中国项目经理大会演讲嘉宾&#xff0c;演讲议题为“激活关键的少数派——项目经理培养体系的设计实践”。大会…

无人机视角下落水救援检测数据集

无人机视角下落水救援检测数据集&#xff0c;利用无人机快速搜索落水者对增加受害者的生存机会至关重要&#xff0c;该数据集共收集12万帧视频图像&#xff0c;涵盖无人机高度从10m-60m高度&#xff0c;检测包括落水者&#xff08;11万标注量&#xff09;、流木&#xff08;900…

TCP/IP - ICMP

目录 1. 帧格式2. ICMPv4消息类型(Type = 0,Code = 0)回送应答 /(Type = 8,Code = 0)回送请求(Type = 3)目标不可达(Type = 5)重定向(Type = 11)ICMP超时(Type = 12)参数3. ICMPv6消息类型回见TCP/IP 对ICMP协议作介绍 ICMP(Internet Control Message Protocol…

什么是快充协议,最常见的快充协议有哪些

什么是快充协议 随着手机快充的出现大家都知道快充技术但很多人确不知道快充协议&#xff0c;在快充技术里快充协议是必不可少的&#xff0c;那么今天我们就来探讨一下什么是快充协议&#xff1f; 快充协议是一种通过提高充电效率来缩短设备充电时间的电池充电技术。它通过在充…

商淘云九周年 分账系统助力企业合规发展

从2015到2024年&#xff0c;商淘云电商服务品牌已走过整整九个春秋。这九年&#xff0c;是商淘云不断发展壮大&#xff0c;深化品牌建设服务&#xff0c;并取得显著成效的九年&#xff0c;也是见证中国电商迅速崛起的九年。我们回顾九年的风雨历程&#xff0c;感受到企业的成长…

Python计算机视觉 第9章-图像分割

Python计算机视觉 第9章-图像分割 图像分割是将一幅图像分割成有意义区域的过程。区域可以是图像的前景与背景或图像中一些单独的对象。这些区域可以利用一些诸如颜色、边界或近邻相似性等特征进行构建。 9.1 图割&#xff08;Graph Cut&#xff09; 图割&#xff08;Graph…

SOMEIP_ETS_111: SD_Empty_Entries_Array

测试目的&#xff1a; 验证DUT能够忽略声明了条目数组长度为零的SubscribeEventgroup消息。 描述 本测试用例旨在确保DUT在接收到一个Entries数组长度为零的SubscribeEventgroup消息时&#xff0c;能够正确地忽略该消息&#xff0c;不对其进行解释或响应。 测试拓扑&#x…

【机器学习-监督学习】朴素贝叶斯

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈Python机器学习 ⌋ ⌋ ⌋ 机器学习是一门人工智能的分支学科&#xff0c;通过算法和模型让计算机从数据中学习&#xff0c;进行模型训练和优化&#xff0c;做出预测、分类和决策支持。Python成为机器学习的首选语言&#xff0c;…

数据中台建设(七)——数据体系建设

数据体系建设 数据中台是企业数据汇集地&#xff0c;但并不是简单的数据堆积&#xff0c;而是进行分层建模&#xff0c;数据体系建设最终呈现一套完整、规范、准确的数据。数据体系建设就是大数据中数据仓库建设。如下图&#xff1a; 贴源数据层ODS(Operational Data Store)…