【PA交易】BackTrader的交易管理

news2024/10/10 22:20:13

前言

本主要讨论BackTrader中的Broker定制化。如果你已经对于BackTrader的交易管理非常熟悉,并且自己有了成熟的适配方案,那么并不需要看这篇文章。但是如果你还没有深入研究过,那么这篇文章可能会给到你启发。

背景与需求

网上现存大量资源详尽介绍了BackTrader的订单和交易模块。笔者无意再去额外写一篇冗余的基础教程来污染中文网络。如果读者对于交易管理相关模块尚未不熟悉,可以参考对应的官网教程Broker - Backtrader、Orders - General - Backtrader以及搜索包括CSDN在内的大量中文资源讲解。

笼统的讲,BackTrader提供了一个Broker模块来模拟处理资金、账户、买卖等等操作。同时BackTrader也提供了Live Trading - Oanda v1.0 - Backtrader等其他对接一些国外外汇交易商的Broker接口。

但目前BackTrader提供的bt.BackBroker的实现直接使用和适配起来却略显复杂和缺乏灵活性。

另一方面,如果我们想要对接CTP的模拟或者实盘接口,显然目前BT并没有直接提供一个合适的Broker来提供这个功能。

更进一步的,BackTrader提供的Order类型包含了大量和外汇交易紧密相关的概念和逻辑,这对于我们的需求属实有些多余,也十分容易引起混淆。强行去将一些概念与我们的内盘期货交易习惯相对应也非常多余。

定制化Broker

出于打造自己的回测和交易框架系统的目的,有必要定制一个独立的Broker。这个定制化的Broker可以接管包括订单、TPSL、资金管理、基础统计等全部功能。当然我们不会从头书写这个类,因为这将脱离框架的一些自动化流程,而是采用继承BackTrader的bt.BrokerBase类的方式

虽然我们的Broker主要专注于回测,但是掌握了改写方法,也很容易实现一个针对CTP模拟或者实盘交易的Broker适配器。

定制化的根本的原因在于,实现起来非常简单且清晰,高度可控。毕竟交易的事情,自己全拿在自己手里才是最稳妥的!而回测,越是按照市场规则的定制,越准确!

本文仅分析框架的类层次和如何继承和定义一个定制化的Broker,不会讨论Broker实现细节。


BackTrader的交易管理

首先,关于交易管理BackTrader提供了Order用于表示订单数据,Broker处理交易的各种操作,一个简单的类层次关系如图所示:

上图左侧的几个Broker是BackTrader用于交易的几个实现,其中IBBroker更像一个通用的交互式可用于实盘交易的实现。如果感兴趣直接使用这个Broker可以参考:Live Trading - Interactive Brokers - Backtrader

但是即使直接使用这个Broker,灵活性依然不足,因为市场差异本身较大,仍然需要大量的定制化工作。而这些定制化工作所需要的时间,并不会比直接继承bt.BrokerBase,进而自行实现一些逻辑来的轻松。

首先简单地了解一下目前框架所提供的实体,并分析我们需要哪些功能,不需要哪些功能。

订单实体Orders

如上图所示,订单的类层次机构结构如图所示,从下往上:

  • SellOrder和BuyOrder:指明了Order的多空类型,并直接继承了Order类
  • Order类:处理了拆单、超时和移动止损三个部分。
  • OrderBase类:
    • 核心实现,实际数据的存储封装在了OrderData类中,
    • 实现中使用created(OrderData)和executed(OrderData)两个属性分别作为挂单和成交单。

其中Order类在BackTrader的回测Broker中是需要的,因为这个类中模拟了执行订单的行为。后面会提到,我们更希望将订单的状态、行为、操作等切换成为i更类似于内盘期货市场的风格,这样更加符合我们一般在交易软件中的操作习惯,比如文华。并且把交易的所有操作都提升到Broker层面去执行,Orders仅做为数据载体。这样的好处在于:

  • 回测过程中,更方便去利用Tick中的挂单数量信息实现真实模拟;
  • 在模拟和实盘中,可以利用到CTP返回的成交结果。

我们将继承OrderBase类,在本文中会定制一个非常简单的MyOrder类型。

  • 注意,完全可以在生产中舍弃框架的Order类。实例中继承OrderBase类仅仅是为了少写一点代码。

经纪商Broker

BackTrader提供的Broker接口会在整个策略运行的生命周期中被使用。BrokerBase类也包含了start、stop、next等生命周期方法,他们在策略运行的对应生命周期时被调用。

交易的核心方法是buy和sell,同时为了保留扩展性,BrokerBase类的实现中为这两个接口预设了可变参数**kwargs。可见BackTrader最初的设计是鼓励这种继承BrokerBase类来实现定制化的Broker的魔改行为的。

我们可以覆盖BrokerBase类的绝大多数方法。显然,包括与手续费相关的计算也会被完全重写。

另外,BackTrader糟糕的将一些没有在BrokerBase类中定义的接口也在其他地方进行了调用。这很糟糕。我们已经初步整理了这些接口,并且也会实现这些接口。下文中使用一个空的MyBroker定义代码来展示所需要实现的接口。


MyBroker

示例策略

我们首先结合我们之前的tick数据源写一个基于五分钟均线的示例策略程序,策略逻辑很简单,5bar均上穿20bar均则买入,下传则卖出(为了方便调试,不同于官网示例是,没有使用框架的CrossOver函数)。这是非常简单的操作。部分代码如下:


class TestStrategy(bt.Strategy):
    def __init__(self):
        """
        为管线数据取别名
        """
        # ...略

    
    def next(self):
        dt = self.get_dt_str()

        if self.sma5_5[-1] is None:
            return

        if dt == self.last_dt5:
            return

        mean_val = np.mean([self.bid[0], self.sma5_5[0], self.sma5_20[0]])
        delta = abs(mean_val - min(self.ask[0], self.sma5_5[0], self.sma5_20[0]))
        # 在5分钟级别上执行双均线系统
        if self.sma5_5[-1] < self.sma5_20[-1] and self.sma5_5[0] > self.sma5_20[0]:
            print('5 cross over 20, buy')
            tp = self.ask[0] + 10 * delta
            sl = self.ask[0] - 5 * delta
            orders = self.buy_bracket(price=self.ask[0],
                                      stopprice=sl,
                                      limitprice=tp
                                      )
            self.orders.append(order.to_dict())
        elif self.sma5_5[-1] > self.sma5_20[-1] and self.sma5_5[0] < self.sma5_20[0]:
            print('5 cross over 20, sell')
            tp = self.bid[0] - 10 * delta
            sl = self.bid[0] + 5 * delta
            orders = self.sell_bracket(price=self.bid[0],
                                        stopprice=sl,
                                        limitprice=tp
                                        )

这是一个非常naive且直白的双均线策略。忽略五分钟KBar的没有完成的情况。在五分钟K线完成后,如果M5均线向上穿M20则买入,如果M5向下穿M20则卖出,同时每笔交易都携带了止盈止损。相信写过策略的朋友都非常熟悉这种入门策略了。

这段程序运行很正常。但是有一些需要调整的地方:

  • 止盈止损创建额外订单

我们在代码中设置了止盈止损,但是似乎是出于一致性和简化API的原因,这两个订单被当框架做Stop和Limit订单创建了实际的Order。无论对于回测的Broker、还是模拟或者实盘,这种实现方式都过于粗放,并且不符合我们“条件单”的习惯,而对于交易分析也会比较容易混淆和混乱。

在MyBroker中,我们会将止盈止损作为订单的一部分,同时交易过程完全由Broker接管并统一调度。因为使用了这个改动,我们也不会在使用*_bracket的两个API,而是直接使用简单的buy和sell接口。之所以这样做的原因可以从框架源码中strategy.*_bracket看到。

  • 杠杆和倍数

虽然示例中没有用到,但是杠杆和倍数是需要的。我们有过外汇交易经验的朋友都知道,乘数和我们熟悉的期货一样,代表一手多少倍,同时交易商还可以支持一个杠杆率,可能是100~400。这个我们内盘商品是没有的。

我们应在MyBroker中定义不同品种对应的倍数,然后将倍数计算后结果添加到资金计算中。

  • 爆仓

虽然不希望看到,但是保证金不足时停止策略运行有助于我们提高回测效率,所以我们需要这个检查,不然的话,如果明明已经爆仓了,还在继续运行策略,也和现实有些出入。

这就需要我们为MyBroker添加针对保证金和总资金的额度检测,当爆仓后,立刻停止运行回测。

  • 安全锁

为了整个软件系统最终能够快速无缝切换进入实盘,我们可以考虑可以在Broker中增加额外的安全锁,如果亏损到达一定数量,则强制锁定所有交易接口。这可以在我们的程序出现BUG时,及时阻止任何可能得损失。产品级别的实现中,安全锁的添加应该独立于交易框架,这样可以避免程序崩溃后或者某个地方跑入死循环,能够及时停止程序阻止交易继续进行。

继承BrokerBase

本系列文章中的继承自BrokerBase的MyBroker主要目的只是回测。篇幅和其他一些很好猜到的原因,此处不给出具体实现,所有实际的内容则会留空,如下:


class MyBroker(bt.BrokerBase):
    def __init__(self, **kwargs):
        super(MyBroker, self).__init__()
        pass

    def set_fund_history(self, fund):
        pass

    def setcash(self, cash):
        pass

    def getcash(self):
        pass

    def get_notification(self):
        return None

    def getvalue(self, datas=None):
        pass

    def getposition(self, data):
        pass

    def add_order_history(self, orders, notify=False):
        pass

    def submit(self, order):
        pass

    def cancel(self, order):
        pass

    def buy(self, owner, data, size, price=None,
            plimit=None, exectype=None, valid=None, tradeid=0,  # 不使用这些参数
            oco=None, trailamount=None, trailpercent=None,  # 不使用这些参数
            **kwargs):
        pass

    def sell(self, owner, data, size, price=None,
             plimit=None, exectype=None, valid=None, tradeid=0,  # 不使用这些参数
             oco=None, trailamount=None, trailpercent=None,  # 不使用这些参数
             **kwargs):
        pass

    # =========================================
    # 新增方法
    def start(self):
        pass

    def stop(self):
        pass

    def next(self):
        # 刷新并计算Value和cash
        # 检查挂单成交情况
        # 根据tick值触发订单TPSL
        pass

注意next函数的注释解释了这个函数需要做的工作。订单的管理可以完全在自定义的Broker中实现,从而实现定制化交易管理的功能。

结语

本文简略介绍了BT中Broker的框架,同时介绍了应该定制化自己的Broker类。文中没有给出具体实现方式,这里的具体实现并不复杂,主要是订单的管理以及资金的刷新。注意,实现时候一个能改关注周期级别,同时为了支持更灵活的分析器使用,一些分析器会用到的接口必须要实现。

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

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

相关文章

【数据结构】(C语言):链表

链表&#xff1a; 基本单位是节点。节点至少两部分&#xff1a;数据&#xff0c;下一个数据的地址。头指针head&#xff0c;始终指向链表的第一个节点。若没有节点&#xff0c;则headNULL。链表在内存中是非连续的。不能使用索引&#xff08;下标&#xff09;查找元素。只能从…

关于application/x-www-form-urlencoded跟application/json请求的区别

当你的java方法是这样定义的 PostMapping("/rePushMedicalRecord") public String rePushMedicalRecord(RequestParam("topicId") String topicId){ } 参数是RequestParam接收&#xff0c;则请求时需要用application/x-www-form-urlencoded请求 如果是R…

【ARMv8/v9 GIC 系列 2.3 -- GIC SPI 中断的 GICD_CLRSPI_NSR寄存器】

文章目录 GICD_CLRSPIN_NSR寄存器功能INTID 位 [12:0]中断触发类型的影响小结 GICD_CLRSPIN_NSR 在 ARMv9 架构下&#xff0c;GIC&#xff08;Generic Interrupt Controller&#xff09;是负责中断管理的关键组件&#xff0c;它支持复杂的中断处理需求&#xff0c;包括多处理器…

OS中断机制-嵌套和竞争

对于FreeRTOS最好不去用中断嵌套,中断嵌套会增加堆栈空间的使用,因为每个中断服务程序都需要保存和恢复寄存器状态,这可能会耗尽有限的堆栈空间,从而导致系统故障。以及中断嵌套时,不同的中断服务程序可能会竞争访问共享资源,从而增加死锁的风险。这可能会导致系统出现故…

第二节课 6月13日 ssh密钥登陆方式

centos和ubuntu openssh服务的初始安装 一、实验&#xff1a;ubuntu系统激活root用户 ubuntu系统如何激活root用户&#xff0c;允许root用户ssh登陆&#xff1f; 1、ubuntu默认root用户未设置密码&#xff0c;未激活 激活root用户&#xff0c;设置root密码 sudo passwd roo…

从零开始做题:修猫

修猫 1 题目 2 解题 2.1 使用Stegslove分析图片 (base) ┌──(holyeyes㉿kali2023)-[~/Misc/tool-misc] └─$ java -jar Stegsolve.jar 2.2 analyse -frame browser 2.3 得到flag DASCTF{818ca3a840e768da7d5fcdeaedd5012f}

37岁,被裁员,失业三个月,被面试官嫌弃“太水”:就这也叫10年以上工作经验?

今年部门要招两个自动化测试&#xff0c;这几个月我面试了几十位候选人。发现一个很奇怪的现象&#xff0c;面试中一问到元素定位、框架api、脚本编写之类的&#xff0c;很多候选人都对答如流。但是一问到实际项目&#xff0c;比如“项目中UI自动化和接口自动化如何搭配使用&am…

前端:HTML、CSS、JavaScript 代码注释 / 注释与代码规范

一、HTML 行内注释 HTML注释是在HTML代码中添加说明和解释的一种方法&#xff0c;这些注释不会被浏览器渲染或显示在页面上&#xff0c;而是被浏览器忽略。HTML注释对于代码的可读性、可维护性和团队协作非常重要。 1.1、HTML注释的语法 HTML注释的语法是以<!--开始&…

【算法与数据结构】【字符串篇】【String的常见函数】

系列文章 本人系列文章-CSDN博客https://blog.csdn.net/handsomethefirst/article/details/138226266?spm1001.2014.3001.5502 1.string基本概念 string是C风格的字符串&#xff0c;而string本质上是一个类。 string和char * 区别&#xff1a; char * 是一个指针 string是一…

OpenAI 收购桌面实时协作公司 Multi;iOS 18 开放 iPhone 镜像测试丨RTE 开发者日报 Vol.231

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE&#xff08;Real-Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

[深度学习] 卷积神经网络CNN

卷积神经网络&#xff08;Convolutional Neural Network, CNN&#xff09;是一种专门用于处理数据具有类似网格结构的神经网络&#xff0c;最常用于图像数据处理。 一、CNN的详细过程&#xff1a; 1. 输入层 输入层接收原始数据&#xff0c;例如一张图像&#xff0c;它可以被…

图片怎么加水印?快来试试这6个图片加水印方法(2024年新)

图片怎么加水印&#xff1f;作为打工人在日常的工作生活中总会遇到各种各样的工作难题&#xff0c;相信从事电商或者是设计等工作的小伙伴们&#xff0c;遇到最多的问题应该就是给图片添加水印了。为什么要给图片加水印&#xff1f;其实给图片加水印最主要的目的是保护我们的图…

Linux集群自动化维护-Ansible

1.1Ansible概述 自动化运维&#xff1a;批量管理&#xff0c;批量分发&#xff0c;批量执行&#xff0c;维护。。是python写的 批量管理工具&#xff1a; Ansible&#xff08;无客户端&#xff09;&#xff1a;无客户端&#xff0c;基于ssh进行管理与维护 Saltstack &#…

深度之眼(二十五)——研究生学习计划安排

文章目录 一、前言二、结构安排和规划2.1 夯实基础2.2 分方向训练&#xff08;待&#xff09;2.3 进阶训练 三、其他 一、前言 课题组这边是需要对机器视觉有所要求吧&#xff0c;也就是CV方向。这一届研三师兄也都是在大厂拿到30W的年薪了&#xff0c;也是需要拥抱深度学习这…

NineData和华为云在一起!提供一站式智能数据库DevOps平台

以GuassDB数据库为底座 NineData和华为云一起 为企业提供 一站式智能数据库DevOps平台 帮助开发者 高效、安全地完成 数据库SQL审核 访问控制、敏感数据保护等 日常数据库相关开发任务 NineData 智能数据管理平台 NineData 作为新一代的云原生智能数据管理平台&#xf…

SpringCloud:Gateway服务网关

程序员老茶 &#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; P   S : 点赞是免费的&#xff0c;却可以让写博客的作者开心好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#…

聚星文社ai工具下载

您可以在聚星文社官方网站上下载他们的AI工具。请访问他们的官方网站&#xff0c; 然后找到下载页面&#xff0c;从中选择并下载所需的AI工具。下载 如果您对下载过程有任何问题&#xff0c;建议您直接联系聚星文社的客服人员寻求帮助。

统信UOS系统忘记登录密码怎么办

在使用统信操作系统UOS的时候有可能会出现忘记密码的情况&#xff0c;当遇到了用户登录密码忘记时如何修改&#xff1f;今天分享一下忘记超级系统管理员Root以及普通密码时的解决方法。 因为UOS系统版本的原因&#xff0c;UOS 1031操作系统取消了单用户更改密码的方法&#xff…

Sulfo Cy3-NHS Ester生物标记与成像

【星戈瑞stargraydye】以下数据均来自文献资料,星戈瑞暂未进行独立验证, 仅供参考&#xff01; 在生物医学研究的前沿领域&#xff0c;荧光标记技术扮演着科研角色。其中&#xff0c;Sulfo Cy3 NHS Ester作为一种性能的荧光染料&#xff0c;以其高灵敏度、高特异性以及良好的生…

绿色共享购:共创绿色消费新纪元

在当今快节奏的社会中&#xff0c;人们对绿色消费和共享经济的追求愈发凸显其重要性。为了满足这一需求&#xff0c;我们创新推出了“绿色共享购”这一前沿的消费增值模式。该模式不仅有效整合了商家资源&#xff0c;更通过其独特的机制&#xff0c;实现了商家与消费者的双重增…