lesson01 Backtrader是什么

[Backtrader]专题连载

Backtrader是什么?

Backtrader 是 2015 年开源的 Python 量化回测框架(支持实盘交易)。专注于为量化交易策略提供回测和实盘交易功能。它允许用户集中精力编写可复用的交易策略、指标和分析工具,而无需花费时间构建基础设施。

Backtrader 主要特点

  • 丰富的功能:支持股票、期货、期权、外汇、数字货币等多种交易品种,以及从Ticks级到年度的不同时间周期
  • 高效的性能:利用pandas的矢量运算和多策略并行运算,提供快速的回测能力
  • 灵活的组件:内置了Ta-lib技术指标库、PyFlio分析模块、plot绘图模块和参数优化等工具
  • 策略开发:用户可以创建策略类,编写策略逻辑,并通过Cerebro引擎运行回测
  • 数据源:支持多种数据源,允许用户添加数据源到Cerebro引擎,并进行交易
  • 指标和交易:Backtrader提供了大量的内置指标,用户可以在策略中使用这些指标,或自定义新的指标
  • 可视化:Backtrader可以绘制策略的交易图表,帮助用户进行视觉检查

Backtrader 核心组件

在此,先了解 Backtrader 几个核心组件:

  • Cerebro:BackTrader的基石,所有的操作都是基于Cerebro的。
  • Feed:将运行策略所需的基础数据加载到Cerebro中,一般为K线数据。
  • Indicator:BackTader自带的指标,并集成了talib中的指标。我们也可以选择继承一个Indicator实现自己的指标。
  • Strategy:交易策略。这里是整个过程中最复杂的部分,需要我们计算买入/卖出信号。
  • Analyzer:分析器,以图形和风险收益等指标对交易策略的回测结果进行分析评价。
  • Order:订单,记录了与当前订单相关的所有数据。
  • Trader:交易,记录了与当前交易相关的所有数据。
  • Position:持仓,记录了与当前持仓相关的所有数据。
  • Broker:可以理解成经纪人,整个策略的初始资金、交易费率、滑点等参数需要通过Broker进行设置。
  • Observer:观察者,对数据进行监控观察,比如资金曲线等等。
  • Plotting:可视化组件

Backtrader 回测代码流程

Backtrader 以 cerebro 为统一的调度中心,数据、策略、回测条件等信息都会导入 cerebro 中,并由 cerebro 启动和完成回测,最后返回回测结果。

Backtrader 回测代码流程

Backtrader 第一个Demo

  • 股票池:中证500成分股

  • 回测区间:20190101-2021-01-28

  • 持仓周期:月度调仓,每月第一个交易日,以开票价买入或卖出

  • 持仓权重:流通市值占比

  • 总资产:100万元

  • 佣金:0.0003 双边

  • 滑点:0.0001 双边

  • 策略逻辑:假设已经在每个月最后一个交易日基于选股规则选出了中证500成分股中表现优异的前20%的股票作为下一个月的持仓成分股,然后在下个月的第一个交易日,卖出已持仓,买入新的持仓。

import backtrader as bt
import pandas as pd
import numpy as np
import datetime
from copy import deepcopy

准备数据

1、日度行情数据集

数据集 daily_price.csv,日度行情数据(后复权),共有 8 个字段,除 sec_code 字段外,其余 7 个字段是 Data Feeds 导入 DataFrame 数据时默认必须包含的字段。

导入多只股票的历史行情数据:

  • 导入的 DataFrame 有默认的格式要求:
    • 1)以交易日 ‘datetime’ 为 index;
    • 2)列为 ‘open’、‘high’、‘low’、‘close’、‘volume’、‘openinterest’ 字段
  • 采用的是循环导入的方式,每次循环导入一只股票的数据并将数据名称命名为股票名。

2、月末调仓成分股数据集

数据集 trade_info.csv,包含 3 个字段:trade_date 调仓期(每月最后一个交易日)、sec_code 持仓成分股代码、weight 持仓权重

daily_price = pd.read_csv('./data/daily_price.csv', parse_dates=['datetime'])
daily_price = daily_price.set_index(['datetime'])trade_info = pd.read_csv('./data/trade_info.csv',parse_dates=['trade_date'])

编写交易逻辑

选股策略

所有的交易策略都是写在自定义的策略类里,如下面的 TestStrategy 类,自定义的策略类名称可以任意取,但必须继承 Backtrader 内置的 Strategy 类,即 bt.Strategy 。

在TestStrategy 里至少需要定义 init() 和 next() 方法。其中, init() 用于初始化各类属性,next() 用于下单交易。

具体到选股策略:

    1. trade_info.csv 里的调仓日和持仓列表就可以定义在 init() 里,方便 next() 函数调用;
    1. 在 next() 里,判断每个交易日是否为调仓日,如果是调仓日就按调仓权重卖出旧股,买入新股。

打印回测日志

在 TestStrategy 里还可以定义许多打印日志的函数,常用的有 notify_order() 订单日志、notify_trade() 交易日志、notify_cashvalue() 资金信息、notify_store() 交易事件说明等等。

提取回测结果,首先要确保已经启动并完成回测,然后再从返回的 result 中提取事先配置好的回测结果。

import backtrader.indicators as btind # 导入策略分析模块
import backtrader.feeds as btfeeds # 导入数据模块class TestStrategy(bt.Strategy):# 可选,设置回测的可变参数:如移动均线的周期params = (('buy_stocks',None), # 传入各个调仓日的股票列表和相应的权重)def log(self, txt, dt=None):'''可选,构建策略打印日志的函数:可用于打印订单记录或交易记录等'''dt = dt or self.datas[0].datetime.date(0)print('{},{}'.format(dt.isoformat(),txt))def __init__(self):'''必选,初始化属性、计算指标等'''# 读取调仓日期,即每月的最后一个交易日,回测时,会在这一天下单,然后在下一个交易日,以开盘价买入self.trade_dates = pd.to_datetime(self.p.buy_stocks['trade_date'].unique()).to_list()# 保留调仓信息self.buy_stock = self.p.buy_stocks # 记录以往订单,在调仓日要全部取消未成交的订单self.order_list = []# 记录上一期持仓self.buy_stocks_pre = []# 订单日志def notify_order(self, order):# 未被处理的订单if order.status in [order.Submitted, order.Accepted]:return# 已被处理的订单if order.status in [order.Completed,order.Canceled,order.Margin]:if order.isbuy():self.log('Buy Executed, ref:%.0f, Price: %.2f, Cost: %.2f, Comm %.2f, Size: %.2f, Stock: %s' %(order.ref,order.executed.price,order.executed.value,order.executed.comm,order.executed.size,order.data._name))else:self.log('Sell Executed, ref:%.0f, Price: %.2f, Cost: %.2f, Comm %.2f, Size: %.2f, Stock: %s' %(order.ref,order.executed.price,order.executed.value,order.executed.comm,order.executed.size,order.data._name))def next(self):'''必选,编写交易策略逻辑'''# 获取当前的回测时间点dt = self.datas[0].datetime.date(0)# 打印当前时刻的总资产self.log('当前总资产 %.2f' %(self.broker.getvalue()))# 如果是调仓日,则进行调仓操作if dt in self.trade_dates:print('--{} 为调仓日---'.format(dt))# 1.取消之前所下的没成交也未到期的订单if len(self.order_list)>0:print('---撤销未完成的订单---')for order in self.order_list:self.cancel(order)self.order_list=[]# 2.提取当前调仓日的持仓列表buy_stocks_data = self.buy_stock.query(f"trade_date=='{dt}'")long_list = buy_stocks_data['sec_code'].tolist()print('long_list',long_list)# 3.对现有持仓中,调仓后不再继续持有的股票进行卖出平仓sell_stock = [i for i in self.buy_stocks_pre if i not in long_list]print('sell_stock',sell_stock)if len(sell_stock)>0:print('---对不再持有的股票进行平仓---')for stock in sell_stock:data = self.getdatabyname(stock)if self.getposition(data).size > 0:order = self.close(data=data)self.order_list.append(order)# 4.买入此次调仓的股票:多退少补原则print('---买入此次调仓的股票---')for stock in long_list:weight = buy_stocks_data.query(f"sec_code=='{stock}'")['weight'].iloc[0]data = self.getdatabyname(stock)order = self.order_target_percent(data=data,target=weight * 0.95)self.order_list.append(order)self.buy_stocks_pre = long_list

导入数据

# 实例化 cerebro
cerebro = bt.Cerebro()for stock in daily_price['sec_code'].unique():# 日期对齐data = pd.DataFrame(index=daily_price.index.unique())df = daily_price.query(f"sec_code=='{stock}'")[['open','high','low','close','volume','openinterest']]data_ = pd.merge(data, df, left_index=True, right_index=True, how='left')data_.loc[:,['volume','openinterest']] = data_.loc[:,['volume','openinterest']].fillna(0)data_.loc[:,['open','high','low','close']] = data_.loc[:,['open','high','low','close']].fillna(method='pad')data_.loc[:,['open','high','low','close']] = data_.loc[:,['open','high','low','close']].fillna(0)datafeed = bt.feeds.PandasData(dataname=data_, fromdate=datetime.datetime(2019,1,2),todate=datetime.datetime(2021,1,28))cerebro.adddata(datafeed,name=stock)

配置回测条件

# 通过经纪商设置初始资金
cerebro.broker.setcash(100000000.0)
# 佣金,双边各 0.0003
cerebro.broker.setcommission(commission=0.0003) 
# 滑点:双边各 0.0001
cerebro.broker.set_slippage_perc(perc=0.0001) # 添加策略
cerebro.addstrategy(TestStrategy, buy_stocks=trade_info)# 添加策略分析指标
cerebro.addanalyzer(bt.analyzers.TimeReturn, _name='pnl')
cerebro.addanalyzer(bt.analyzers.AnnualReturn, _name='_AnnualReturn')
cerebro.addanalyzer(bt.analyzers.SharpeRatio, riskfreerate=0.003, annualize=True, _name='_SharpeRatio')
cerebro.addanalyzer(bt.analyzers.DrawDown, _name='_DrawDown')# 添加观测器
cerebro.addobserver(bt.observers.Value)

运行回测

# 启动回测
result = cerebro.run()

提取回测结果

stats = result[0]
print('--AnnualReturn---')
print(stats.analyzers._AnnualReturn.get_analysis())
print('---SharpRatio---')
print(stats.analyzers._SharpeRatio.get_analysis())
print('--DrawDown---')
print(stats.analyzers._DrawDown.get_analysis())
--AnnualReturn---
OrderedDict([(2019, 0.2421668400755459), (2020, 0.2154227563253983), (2021, 0.017567210073598405)])
---SharpRatio---
OrderedDict([('sharperatio', 1.5512121051534205)])
--DrawDown---
AutoOrderedDict([('len', 136), ('drawdown', 6.655064560819013), ('moneydown', 10952970.349310696), ('max', AutoOrderedDict([('len', 206), ('drawdown', 20.374812759676267), ('moneydown', 27705182.493407518)]))])
# https://blog.csdn.net/weixin_42829932/article/details/128515915
# 可视化回测结果
%matplotlib inline
cerebro.plot(iplot=True)[0][0]

Q&A

在导入多只股票数据时需注意?

  • 各股交易日不统一:上市日期不一致、退市日期不一致、回测区间内出现停牌等,都会使得不同股票各自的交易日数量不统一,所以要以回测区间内所有交易日为基础,对每只股票缺失的交易日进行补齐;
  • 行情数据缺失:在补齐交易日过程中,会使得补充的交易日缺失行情数据,需对缺失数据进行填充。比如将缺失的 volume 填充为 0,表示股票无法交易的状态;将缺失的高开低收做前向填充;将上市前缺失的高开低收填充为 0 等;
  • 股票与行情数据的匹配:通过设置 adddata() 方法中 name 参数,来实现数据集与股票的一 一对应关系。

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

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

相关文章

衡石分析平台系统分析人员手册-可视化报表仪表盘

仪表盘​ 仪表盘是数据分析最终展现形式,是数据分析的终极展现。 应用由一个或多个仪表盘展示,多个仪表盘之间有业务关联。 仪表盘编辑​ 图表列表​ 打开仪表盘后,就会看到该仪表盘中所有的图表。 调整图表布局​ 将鼠标移动到图表上拖动…

能源领域新政策,我们应该关注什么?

近日,国家发展改革委和国家能源局联合发布了《能源重点领域大规模设备更新实施方案》的通知。该方案指出,能源科技领域是大规模设备更新和消费品以旧换新行动实施的关键领域。 《方案》设定了到2027年,能源重点领域设备投资规模较2023年增长2…

CentOS 8 Stream环境下通过yum安装Mysql

1.在Mysql下载页面MySQL :: Download MySQL Community Server页尾 点击 “MD5 checksums and GnuPG signatures” 进入下一页面 2.打开下载yum repo文件页面 (MySQL :: Download MySQL Yum Repository) 3.点击"DownLoad"按钮,打开下载页面, 4.…

2012年国赛高教杯数学建模C题脑卒中发病环境因素分析及干预解题全过程文档及程序

2012年国赛高教杯数学建模 C题 脑卒中发病环境因素分析及干预 脑卒中(俗称脑中风)是目前威胁人类生命的严重疾病之一,它的发生是一个漫长的过程,一旦得病就很难逆转。这种疾病的诱发已经被证实与环境因素,包括气温和湿…

如何利用kafka实现高效数据同步?

在我们之前的文章有详细介绍过Kafka的结构、特点和处理方式。具备告诉处理能力的kafka被利用在数据同步和数据传输上,今天来说下kafka是怎么实现高效的数据同步和传输。 一、可靠的数据传输 1. 持久性保证:Kafka 将数据持久化到磁盘上,即使在…

深度学习实战94-基于图卷积神经网络GCN模型的搭建以及在金融领域的场景

大家好,我是微学AI,今天给大家介绍一下深度学习实战94-基于图卷积神经网络GCN模型的搭建以及在金融领域的场景。文章首先介绍了GCN模型的原理及模型结构,随后提供了数据样例,并详细展示了实战代码。通过本文,读者可以深入了解GCN模型在金融场景下的应用,同时掌握代码的具…

wifi、热点密码破解 - python

乐子脚本,有点小慢,试过多线程,系统 wifi 连接太慢了,需要时间确认,多线程的话系统根本反应不过来。 也就可以试试破解别人的热点,一般都是 123456 这样的傻鸟口令 # coding:utf-8 import pywifi from pyw…

BF 算法

目录 BF算法 算法思路 完整代码 时间复杂度 查找所有起始位置 BF算法 BF算法:即暴力(Brute Force)算法,是一种模式匹配算法,将目标串 S 的第一个字符与模式串 T 的第一个字符进行匹配,若相等,则继续比较 S 的第二…

【最新华为OD机试E卷-支持在线评测】TLV解码(100分)多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 💻 ACM金牌🏅️团队 | 大厂实习经历 | 多年算法竞赛经历 ✨ 本系列打算持续跟新华为OD-E/D卷的多语言AC题解 🧩 大部分包含 Python / C / Javascript / Java / Cpp 多语言代码 👏 感谢大家的订阅➕ 和 喜欢�…

【git】如何快速准确的回退(reverse)已经合并(merge)主分支(master)的新提交代码

文章目录 前言一、merge模式二、回滚步骤总结 前言 我们在做一些需求,正常流程经过开发,测试到最后和代码上线。但是有时候就会发生一些小插曲,比如产品说老板说某某某你的代码要延后上线!!或者你写的不合格预发环境出…

在Openshift(K8S)上通过EMQX Operator部署Emqx集群

EMQX Operator 简介 EMQX Broker/Enterprise 是一个云原生的 MQTT 消息中间件。 我们提供了 EMQX Kubernetes Operator 来帮助您在 Kubernetes 的环境上快速创建和管理 EMQX Broker/Enterprise 集群。 它可以大大简化部署和管理 EMQX 集群的流程,对于管理和配置的知…

ubuntu 安装keepalived+haproxy

一、安装keepalived sudo apt update sudo apt install keepalived sudo systemctl start keepalived sudo systemctl enable keepalived sudo systemctl status keepalived#配置Keepalived sudo cp /etc/keepalived/keepalived.conf.sample /etc/keepalived/keepalived.conf …

Java面试宝典-并发编程学习02

目录 21、并行与并发有什么区别? 22、多线程中的上下文切换指的是什么? 23、Java 中用到的线程调度算法是什么? 24、Java中线程调度器和时间分片指的是什么? 25、什么是原子操作?Java中有哪些原子类? 26、w…

Python案例小练习——小计算器

文章目录 前言一、代码展示二、运行展示 前言 这是用python实现一个简单的计器。 一、代码展示 def calculate(num1, op, num2):if op "":return float(num1) float(num2)elif op "-":return float(num1) - float(num2)elif op "*":return…

【Mac苹果电脑安装】DBeaverEE for Mac 数据库管理工具软件教程【保姆级教程】

Mac分享吧 文章目录 DBeaverEE 数据库管理工具 软件安装完成,打开效果图片Mac电脑 DBeaverEE 数据库管理工具 软件安装——v24.21️⃣:下载软件2️⃣:安装JDK,根据下图操作步骤提示完成安装3️⃣:安装DBeaverEE&#…

C++类域访问方式(public,protected,private)对象访问 , 通过成员函数访问 ,通过友元函数访问

c类的用法 yC 类的基础用法与详细说明:简单易懂的入门指南-CSDN博客 类的基本概念👇 类是C中的一个用户定义的数据类型,它可以包含数据(成员变量)和函数(成员函数)。通过类,我们可以…

【Jenkins】windows安装步骤

【Jenkins】windows安装步骤 官网使用WAR包方式运行浏览器访问Jenkinswindows-installer安装安装过程问题解决This account either does not hava the privilege to logon as a service or the account was unable to be verified 安装成功修改jenkins.xml启动jenkins访问jenki…

springboot030甘肃非物质文化网站的设计与开发(论文+源码)_kaic

毕 业 设 计(论 文) 题目:甘肃非物质文化网站设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本甘肃非物质文化…

Java基于SSM框架的教学辅助微信小程序【附源码、文档】

博主介绍:✌IT徐师兄、7年大厂程序员经历。全网粉丝15W、csdn博客专家、掘金/华为云//InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇&#x1f3…

vim实用笔记

函数跳转功能 想要使用函数跳转功能需要先安装 ctags sudo apt-get install exuberant-ctags接着,在源文件目录树执行如下命令: ctags -R . 即可在该目录下生成一个tags文件, 这个文件就是所有函数和变量的索引 接着打开用vim打开任一文件…