Backtrader 文档学习- Observers

Backtrader 文档学习- Observers

1.概述

在backtrader中运行的策略主要处理数据源和指标。
数据源被加载到Cerebro实例中,并最终成为策略的一部分(解析和提供实例的属性),而指标则由策略本身声明和管理。
到目前为止,所有backtrader示例图表都有三个默认绘制的东西,因为它们没有在任何地方声明,默认执行:

  • 现金和价值(经纪人中的资金情况)
  • 交易(也称为操作)
  • 买入/卖出订单
    它们是Observers观察者,存在于子模块backtrader.observers中。它们存在是因为Cerebro支持一个参数来自动添加(或不添加)它们到策略中:
  • stdstats(默认值:True)
    如果默认值被使用,Cerebro将执行以下等效的用户代码:
import backtrader as bt...cerebro = bt.Cerebro()  # default kwarg: stdstats=Truecerebro.addobserver(bt.observers.Broker)
cerebro.addobserver(bt.observers.Trades)
cerebro.addobserver(bt.observers.BuySell)

观察带有这三个默认观察者的常规图表(即使没有下达订单,没有交易发生,现金和组合价值也没有变化)

from __future__ import (absolute_import, division, print_function,unicode_literals)
%matplotlib inline
import backtrader as bt
import backtrader.feeds as btfeedsif __name__ == '__main__':cerebro = bt.Cerebro() # stdstats=Falsecerebro.addstrategy(bt.Strategy)data = bt.feeds.BacktraderCSVData(dataname='./datas/2006-day-001.txt')cerebro.adddata(data)cerebro.run()cerebro.plot(iplot=False)

图示:
在这里插入图片描述
在创建Cerebro实例时将stdstats的值更改为False(也可以在调用run时完成):

cerebro = bt.Cerebro(stdstats=False)

在这里插入图片描述

2.Accesing the Observers

观察者在默认情况下已经存在,并收集可用于统计目的的信息,这就是为什么可以通过策略的一个属性来访问观察者:

  • stats

它只是一个占位符。如果回想一下如何添加默认的观察者:

...
cerebro.addobserver(backtrader.observers.Broker)
...

显然问题是如何访问Broker观察者。例如,如何从策略的next方法中执行此操作:

class MyStrategy(bt.Strategy):def next(self):if self.stats.broker.value[0] < 1000.0:print('WHITE FLAG ... I LOST TOO MUCH')elif self.stats.broker.value[0] > 10000000.0:print('TIME FOR THE VIRGIN ISLANDS ....!!!')

Broker观察者就像数据、指标和策略本身一样,也是一个Lines对象。在这种情况下,Broker有2条线:

  • cash
  • value

3.Observer Implementation

实现与指标非常相似:

class Broker(Observer):alias = ('CashValue',)lines = ('cash', 'value')plotinfo = dict(plot=True, subplot=True)def next(self):self.lines.cash[0] = self._owner.broker.getcash()self.lines.value[0] = value = self._owner.broker.getvalue()

步骤:

  • 从Observer(而不是Indicator)派生
  • 根据需要声明行和参数(Broker有2行但没有参数)
  • 将自动属性_owner,设置为持有观察者的策略

注意:_owner的属性

观察者开始工作:

  • 在所有指标计算完成后
  • 在策略next方法执行后
  • 意味着:在循环结束时…观察到发生了什么
    在Broker中,只是机械地记录在每个时间点上经纪人现金和组合价值。

4.Adding Observers to the Strategy

如上所指出的,Cerebro使用stdstats参数来决定是否添加3个默认的观察者,减轻了最终用户的工作。
添加其他观察者是可能的,无论是沿着stdstats还是删除它们。
让我们采用通常的策略,当close价格超过SimpleMovingAverage时购买,如果相反则卖出。
增加一个观察者:

  • DrawDown 回撤,它是backtrader 生态系统中已经存在的观察者
from __future__ import (absolute_import, division, print_function,unicode_literals)import argparse
import datetime
import os.path
import time
import sysimport backtrader as bt
import backtrader.feeds as btfeeds
import backtrader.indicators as btind%matplotlib inlineclass MyStrategy(bt.Strategy):params = (('smaperiod', 15),)def log(self, txt, dt=None):''' Logging function fot this strategy'''dt = dt or self.data.datetime[0]if isinstance(dt, float):dt = bt.num2date(dt).date()print('%s, %s' % (dt.isoformat(), txt))def __init__(self):# SimpleMovingAverage on main data# Equivalent to -> sma = btind.SMA(self.data, period=self.p.smaperiod)sma = btind.SMA(period=self.p.smaperiod)# CrossOver (1: up, -1: down) close / smaself.buysell = btind.CrossOver(self.data.close, sma, plot=True)# Sentinel to None: new ordersa allowedself.order = Nonedef next(self):# Access -1, because drawdown[0] will be calculated after "next"self.log('DrawDown: %.2f' % self.stats.drawdown.drawdown[-1])self.log('MaxDrawDown: %.2f' % self.stats.drawdown.maxdrawdown[-1])# Check if we are in the marketif self.position:if self.buysell < 0:self.log('SELL CREATE, %.2f' % self.data.close[0])self.sell()elif self.buysell > 0:self.log('BUY CREATE, %.2f' % self.data.close[0])self.buy()def runstrat():cerebro = bt.Cerebro()data = bt.feeds.BacktraderCSVData(dataname='./datas/2006-day-001.txt')cerebro.adddata(data)cerebro.addobserver(bt.observers.DrawDown)cerebro.addstrategy(MyStrategy)cerebro.run()cerebro.plot(iplot=False)if __name__ == '__main__':runstrat()

图表的输出显示了回撤的演变
在这里插入图片描述
输出:

... ...
2006-12-12, DrawDown: 0.63
2006-12-12, MaxDrawDown: 2.62
2006-12-13, DrawDown: 0.63
2006-12-13, MaxDrawDown: 2.62
2006-12-14, DrawDown: 0.56
2006-12-14, MaxDrawDown: 2.62
2006-12-15, DrawDown: 0.22
2006-12-15, MaxDrawDown: 2.62
2006-12-18, DrawDown: 0.00
2006-12-18, MaxDrawDown: 2.62
2006-12-19, DrawDown: 0.00
2006-12-19, MaxDrawDown: 2.62
2006-12-20, DrawDown: 0.10
2006-12-20, MaxDrawDown: 2.62
2006-12-21, DrawDown: 0.39
2006-12-21, MaxDrawDown: 2.62
2006-12-22, DrawDown: 0.21
2006-12-22, MaxDrawDown: 2.62
2006-12-27, DrawDown: 0.28
2006-12-27, MaxDrawDown: 2.62
2006-12-28, DrawDown: 0.65
2006-12-28, MaxDrawDown: 2.62
2006-12-29, DrawDown: 0.06
2006-12-29, MaxDrawDown: 2.62

注意:
如文本输出和代码中所示,DrawDown观察者实际上有2条线:

  • drawdown
  • maxdrawdown
    选择不绘制最大回撤线,但使其可供用户使用。
    实际上maxdrawdown的最后一个值也可以通过一个直接属性(而不是一条线)来获得,该属性的名称为maxdd

5.Developing Observers

上面展示了Broker观察者的实现。为了产生有意义的观察者,实现可以使用以下信息:

  • self._owner是当前正在执行的策略
    策略中的任何内容都可以用于观察者

  • 策略中可用的默认内部内容可能有用:

    • broker-> 属性,提供对策略创建订单的broker实例的访问
      如在Broker中所见,通过调用方法getcash和getvalue收集现金和组合值
  • _orderspending-> 策略创建的订单列表,broker已向策略通知事件。
    BuySell观察者遍历列表,查找已执行(完全或部分)的订单,以创建给定时间点(索引0)的平均执行价格

  • _tradespending-> 交易列表(已完成的买入/卖出或卖出/买入对的集合),从买入/卖出订单编译而成
    观察者可以通过self._owner.stats路径访问其他观察者。

6.Custom OrderObserver

标准的BuySell观察者只关心已执行的操作。可以创建一个观察者,显示订单何时创建以及它们是否过期。
为了可见性,显示将不会沿价格轴上绘制,而是在单独的轴上绘制。

from __future__ import (absolute_import, division, print_function,unicode_literals)import datetimeimport backtrader as bt
import backtrader.feeds as btfeeds
import backtrader.indicators as btind#直接放在一个程序中。
#from backtrader.orderobserver import OrderObserver
%matplotlib inlineclass MyStrategy(bt.Strategy):params = (('smaperiod', 15),('limitperc', 1.0),('valid', 7),)def log(self, txt, dt=None):''' Logging function fot this strategy'''dt = dt or self.data.datetime[0]if isinstance(dt, float):dt = bt.num2date(dt).date()print('%s, %s' % (dt.isoformat(), txt))def notify_order(self, order):if order.status in [order.Submitted, order.Accepted]:# Buy/Sell order submitted/accepted to/by broker - Nothing to doself.log('ORDER ACCEPTED/SUBMITTED', dt=order.created.dt)self.order = orderreturnif order.status in [order.Expired]:self.log('BUY EXPIRED')elif 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))else:  # Sellself.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %(order.executed.price,order.executed.value,order.executed.comm))# Sentinel to None: new orders allowedself.order = Nonedef __init__(self):# SimpleMovingAverage on main data# Equivalent to -> sma = btind.SMA(self.data, period=self.p.smaperiod)sma = btind.SMA(period=self.p.smaperiod)# CrossOver (1: up, -1: down) close / smaself.buysell = btind.CrossOver(self.data.close, sma, plot=True)# Sentinel to None: new ordersa allowedself.order = Nonedef next(self):if self.order:# pending order ... do nothingreturn# Check if we are in the marketif self.position:if self.buysell < 0:self.log('SELL CREATE, %.2f' % self.data.close[0])self.sell()elif self.buysell > 0:plimit = self.data.close[0] * (1.0 - self.p.limitperc / 100.0)valid = self.data.datetime.date(0) + \datetime.timedelta(days=self.p.valid)self.log('BUY CREATE, %.2f' % plimit)self.buy(exectype=bt.Order.Limit, price=plimit, valid=valid)class OrderObserver(bt.observer.Observer):lines = ('created', 'expired',)plotinfo = dict(plot=True, subplot=True, plotlinelabels=True)plotlines = dict(created=dict(marker='*', markersize=8.0, color='lime', fillstyle='full'),expired=dict(marker='s', markersize=8.0, color='red', fillstyle='full'))def next(self):for order in self._owner._orderspending:if order.data is not self.data:continueif not order.isbuy():continue# Only interested in "buy" orders, because the sell orders# in the strategy are Market orders and will be immediately# executedif order.status in [bt.Order.Accepted, bt.Order.Submitted]:self.lines.created[0] = order.created.priceelif order.status in [bt.Order.Expired]:self.lines.expired[0] = order.created.pricedef runstrat():cerebro = bt.Cerebro()data = bt.feeds.BacktraderCSVData(dataname='./datas/2006-day-001.txt')cerebro.adddata(data)cerebro.addobserver(OrderObserver)cerebro.addstrategy(MyStrategy)cerebro.run()cerebro.plot(iplot=False)if __name__ == '__main__':runstrat()

自定义观察者只关心买入订单,因为这是一种只买入以试图获利的策略。卖出订单是市价订单,将立即执行。
Close-SMA CrossOver策略规则更改为:

  • 创建一个价格低于此时刻收盘价1.0%以下的限价订单
  • 订单的有效期为7(日历)天
    在这里插入图片描述

如新子图(红色方块)所示,新增的Observer 对象,created 和 expired ,有几个订单已过期,还看到在创建和执行间隔了几天。

输出结果:

2006-01-26, BUY CREATE, 3605.01
2006-01-26, ORDER ACCEPTED/SUBMITTED
2006-01-26, ORDER ACCEPTED/SUBMITTED
2006-02-02, BUY EXPIRED
2006-03-10, BUY CREATE, 3760.48
2006-03-10, ORDER ACCEPTED/SUBMITTED
2006-03-10, ORDER ACCEPTED/SUBMITTED
2006-03-17, BUY EXPIRED
2006-03-30, BUY CREATE, 3835.86
2006-03-30, ORDER ACCEPTED/SUBMITTED
2006-03-30, ORDER ACCEPTED/SUBMITTED
2006-04-05, BUY EXECUTED, Price: 3835.86, Cost: 3835.86, Comm 0.00
2006-04-07, SELL CREATE, 3823.11
2006-04-07, ORDER ACCEPTED/SUBMITTED
2006-04-07, ORDER ACCEPTED/SUBMITTED
2006-04-10, SELL EXECUTED, Price: 3822.35, Cost: 3835.86, Comm 0.00
2006-04-20, BUY CREATE, 3821.40
2006-04-20, ORDER ACCEPTED/SUBMITTED
2006-04-20, ORDER ACCEPTED/SUBMITTED
2006-04-27, BUY EXPIRED
2006-05-04, BUY CREATE, 3804.65
2006-05-04, ORDER ACCEPTED/SUBMITTED
2006-05-04, ORDER ACCEPTED/SUBMITTED
2006-05-11, BUY EXPIRED
2006-06-01, BUY CREATE, 3611.85
2006-06-01, ORDER ACCEPTED/SUBMITTED
2006-06-01, ORDER ACCEPTED/SUBMITTED
2006-06-05, BUY EXECUTED, Price: 3611.85, Cost: 3611.85, Comm 0.00
2006-06-05, SELL CREATE, 3604.33
2006-06-05, ORDER ACCEPTED/SUBMITTED
2006-06-05, ORDER ACCEPTED/SUBMITTED
2006-06-06, SELL EXECUTED, Price: 3598.58, Cost: 3611.85, Comm 0.00
2006-06-21, BUY CREATE, 3491.57
2006-06-21, ORDER ACCEPTED/SUBMITTED
2006-06-21, ORDER ACCEPTED/SUBMITTED
2006-06-28, BUY EXPIRED
2006-07-24, BUY CREATE, 3596.60
2006-07-24, ORDER ACCEPTED/SUBMITTED
2006-07-24, ORDER ACCEPTED/SUBMITTED
2006-07-31, BUY EXPIRED
2006-09-12, BUY CREATE, 3751.07
2006-09-12, ORDER ACCEPTED/SUBMITTED
2006-09-12, ORDER ACCEPTED/SUBMITTED
2006-09-19, BUY EXPIRED
2006-09-20, BUY CREATE, 3802.90
2006-09-20, ORDER ACCEPTED/SUBMITTED
2006-09-20, ORDER ACCEPTED/SUBMITTED
2006-09-22, BUY EXECUTED, Price: 3802.90, Cost: 3802.90, Comm 0.00
2006-11-02, SELL CREATE, 3974.62
2006-11-02, ORDER ACCEPTED/SUBMITTED
2006-11-02, ORDER ACCEPTED/SUBMITTED
2006-11-03, SELL EXECUTED, Price: 3979.73, Cost: 3802.90, Comm 0.00
2006-11-06, BUY CREATE, 4004.77
2006-11-06, ORDER ACCEPTED/SUBMITTED
2006-11-06, ORDER ACCEPTED/SUBMITTED
2006-11-13, BUY EXPIRED
2006-12-11, BUY CREATE, 4012.36
2006-12-11, ORDER ACCEPTED/SUBMITTED
2006-12-11, ORDER ACCEPTED/SUBMITTED
2006-12-18, BUY EXPIRED

最后,应用新的观察者的策略代码,见前。

7.Saving/Keeping the statistics

保存/保持统计信息到目前为止,backtrader尚未实现任何机制来跟踪观察者的值并将其存储到文件中。最好的方法是:

  • 在策略的start方法中打开文件
  • 在策略的next方法中将值写入
    考虑到DrawDown观察者,可以做:
class MyStrategy(bt.Strategy):def start(self):self.mystats = open('mystats.csv', 'wb')self.mystats.write('datetime,drawdown, maxdrawdown\n')def next(self):self.mystats.write(self.data.datetime.date(0).strftime('%Y-%m-%d'))self.mystats.write(',%.2f' % self.stats.drawdown.drawdown[-1])self.mystats.write(',%.2f' % self.stats.drawdown.maxdrawdown-1])self.mystats.write('\n')

要保存索引0的值,一旦处理完所有观察者,可以将自定义观察者添加为系统中的最后一个观察者,以将值保存到csv文件中。

注意:Writer的功能可以自动化此任务。

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

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

相关文章

rsync-3.1.2下载编译安装运行同步

下载 https://rsync.samba.org/ftp/rsync/src/ 解压 -解压源码包tar -xvf rsync-3.1.2.tar.gz -重命名mv rsync-3.1.2 rsync -将软件安装到指定目录下./configure --prefi/usr -编译 make - 安装 make install 安装之后启动脚本在/usr/bin/ -启动脚本 (启动之前需要配置一下…

SpringBoot注解--04--01--注解@Mapper在IDEA中自动注入警告的解决方案

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 问题原因 解决方案方法1&#xff1a;为 Autowired 注解设置required false方法2&#xff1a;用 Resource 替换 Autowired方法3&#xff1a;在Mapper接口上加上Repo…

一次Kubernetes Pod内存异常导致的测试环境耗时异常问题排查过程

概述 在使用公司内部后台系统测试环境时发现一个请求加载慢的问题&#xff0c;简简单单的列表&#xff0c;查询MongoDB数据库&#xff0c;测试环境不过几百上千条数据而已&#xff0c;请求耗时居然高达5~6秒&#xff1a; 作为对比&#xff0c;生产环境的请求响应截图如下&…

CSRF:跨站请求伪造攻击

目录 什么是CSRF&#xff1f; DVWA中的CSRF low medium hight impossible 防御CSRF 1、验证码 2、referer校验 3、cookie的Samesite属性 4、Anti-CSRF-Token 什么是CSRF&#xff1f; CSRF全称为跨站请求伪造&#xff08;Cross-site request forgery&#xff09;&…

@所有人 您需要的 幻兽帕鲁服务器搭建教程 已上线

所有人 您需要的 幻兽帕鲁服务器搭建教程 已上线 幻兽帕鲁一键购买及部署体验购买及部署购买云服务器ECS部署幻兽帕鲁 创建账户并登录Steam其他操作更新服务器修改游戏参数其他操作释放资源 一直拖到今天才来写这篇幻兽帕鲁服务器搭建教程&#xff0c;确实是因为前段时间有事耽…

2024年美赛数学建模E题思路分析 - 财产保险的可持续性

# 1 赛题 问题E&#xff1a;财产保险的可持续性 极端天气事件正成为财产所有者和保险公司面临的危机。“近年来&#xff0c;世界已经遭受了1000多起极端天气事件造成的超过1万亿美元的损失”。[1]2022年&#xff0c;保险业的自然灾害索赔人数“比30年的平均水平增加了115%”。…

淘宝镜像到期如何切换镜像及如何安装淘宝镜像

淘宝镜像到期如何切换镜像及如何安装淘宝镜像 一、淘宝镜像到期如何切换新镜像二、第一次使用淘宝镜像如何配置镜像 一、淘宝镜像到期如何切换新镜像 清空缓存&#xff1a;npm cache clean --force切换镜像源&#xff1a;npm config set registry https://registry.npmmirror.…

003集—三调数据库添加三大类字段——arcgis

在国土管理日常统计工作中经常需要用到三大类数据&#xff08;农用地、建设用地、未利用地&#xff09;&#xff0c;而三调数据库中无三大类字段&#xff0c;因此需要手工录入三大类字段&#xff0c;并根据二级地类代码录入相关三大类名称。本代码可一键录入海量三大类名称统计…

【Flink入门修炼】1-1 为什么要学习 Flink?

流处理和批处理是什么&#xff1f; 什么是 Flink&#xff1f; 为什么要学习 Flink&#xff1f; Flink 有什么特点&#xff0c;能做什么&#xff1f; 本文将为你解答以上问题。 一、批处理和流处理 早些年&#xff0c;大数据处理还主要为批处理&#xff0c;一般按天或小时定时处…

【Redis】深入理解 Redis 常用数据类型源码及底层实现(3.详解String数据结构)

【Redis】深入理解 Redis 常用数据类型源码及底层实现&#xff08;1.结构与源码概述&#xff09;-CSDN博客 【Redis】深入理解 Redis 常用数据类型源码及底层实现(2.版本区别dictEntry & redisObject详解)-CSDN博客 紧接着前两篇的总体介绍&#xff0c;从这篇开始&#x…

异地办公必不可缺的远程控制软件,原理到底是什么?

目录 引言远程桌面连接软件的作用与重要性 基本概念与架构客户端-服务器模型网络通信协议 核心技术组件图形界面捕获与传输输入转发会话管理 性能优化策略带宽优化延迟优化 引言 远程桌面连接软件的作用与重要性 在当今这个高度数字化和网络化的时代&#xff0c;远程桌面连接软…

Redis核心技术与实战【学习笔记】 - 17.Redis 缓存异常:缓存雪崩、击穿、穿透

概述 Redis 的缓存异常问题&#xff0c;除了数据不一致问题外&#xff0c;还会面临其他三个问题&#xff0c;分别是缓存雪崩、缓存击穿、缓存穿透。这三个问题&#xff0c;一旦发生&#xff0c;会导致大量的请求积压到数据库。若并发量很大&#xff0c;就会导致数据库宕机或故…