股票量化交易进阶001_回测框架backtrader(一)

本文介绍了股票量化交易的回测框架backtrader,包括其组成、使用方法和一个简单的回测示例,强调了backtrader在策略编写和基础设施构建上的优势,鼓励读者通过实践熟悉backtrader。
摘要由CSDN通过智能技术生成


前言

  • 做量化交易有三个重要环节:

    第一、数据源
    有关数据源部分可以了解我之前一个专栏:python股票量化交易入门
    第二、数据回测
    第三、实盘交易

    其中数据回测,目前市面上有一些第三方云平台,以聚宽、优矿、米筐这3个最常见,这3个平台都是Python API的结构,并且有完善的测试结果的可视化工具。
    但是,第三方云平台都是封装了底层代码,如果在你代码运行出现问题想调试的时候,就不能直接修改源码去解决,并且如果你想定制化你个人的一些回测都会受到一定的限制;另外,第三方云平台的网络服务器编译往往没有本地编译快;还有第三方云平台一般都存在收费情况。
    结合第三方云平台的几个问题,你是否想构造一套属于自己的回测框架?或者有没有好的开源的本地回测框架可以使用?


一、backtrader是什么?

用于回测和交易的功能丰富的 Python 框架

backtrader让您可以专注于编写可重复使用的交易策略、指标和分析器,而不必花时间构建基础设施。

二、backtrader的组成

  • 数据加载(DataFeed):
    将交易的数据加载到回测框架中
  • 交易策略(Strategy):
    自己想回测的交易策略,需要得出买卖信号
  • 回测框架设置(Cerebro):
    需要设置初始资金,交易佣金,交易策略,交易头寸大小等
  • 运行回测
    运行Cerebro回测,并打印回测结果
  • 评估性能(Analyzers
    添加计算评估指标并以图形方式展示

三、开始使用backtrader

先用一个简单但有标准的回测代码来进一步了解backtrader。
数据使用tushare的数据

# -*- coding: UTF-8 -*-
"""
@Project :
@File    :backtraderTest1.py
@Author  :johnny2004
@Date    :2022-05-25 0:21 
@desc    : 使用开源框架backtrader回测简单的均线策略
"""
from __future__ import (absolute_import, division, print_function,
                        unicode_literals)

import datetime

import pandas as pd
from matplotlib import pyplot as plt
import tushare as ts

import backtrader as bt

# 设置图表可以中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']


# tushare认证和初始化pro接口
ts.set_token('xxx')
pro = ts.pro_api()


def get_data(code, startDate='2015-01-01', endDate=datetime.date.today()):
    data = pro.query('daily', ts_code=code, start_date=startDate, end_date=endDate)
    # 对股票数据进行整合,符合backtrader
    data.index = pd.to_datetime(data['trade_date'])
    data['openinterest'] = 0
    data['volume'] = data['vol']
    data = data[['open', 'high', 'low', 'close', 'volume', 'openinterest']]
    data = data.sort_index()
    return data


''' 第二步:构建策略   策略:上穿20日均线买入,跌穿20均线就卖出'''


class MyStrategy(bt.Strategy):
    params = (
        ('maPeriod', 20),
    )

    def log(self, txt, dt=None):
        """ Logging function fot this strategy"""
        dt = dt or self.datas[0].datetime.date(0)
        print('%s, %s' % (dt.isoformat(), txt))

    def __init__(self):

        self.ma = bt.indicators.SimpleMovingAverage(self.datas[0], period=self.params.maPeriod)
        # Keep a reference to the "close" line in the data[0] dataseries
        self.dataclose = self.datas[0].close

        # To keep track of pending orders and buy price/commission
        self.order = None
        self.buyprice = None
        self.buycomm = None

    # 监控订单情况
    def notify_order(self, order):
        # 如果订单在提交或者允许的情况下,直接返回
        if order.status in [order.Submitted, order.Accepted]:
            # Buy/Sell order submitted/accepted to/by broker - Nothing to do
            return

        # Check if an order has been completed
        # Attention: broker could reject order if not enough cash

        # 如果下单完成了
        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
            elif order.issell():
                self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
                         (order.executed.price,
                          order.executed.value,
                          order.executed.comm))
                # 记录当前bar的状态,并复制给自身属性bar_executed
                self.bar_executed = len(self)
        # 如果下单的情况在另外状态
        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log('Order Canceled/Margin/Rejected')
            # Write down: no pending order
        # 将订单状态重置为None
        self.order = None

    # 监控交易周期是否完成
    def notify_trade(self, trade):
        # 正在交易返回空
        if not trade.isclosed:
            return
        # 一堆交易结束,输出信息,第一个为毛利润,第二个为净利润(扣除手续费)
        self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
                 (trade.pnl, trade.pnlcomm))

    # 每个bar都会执行一次,回测的每个日期都会执行一次
    def next(self):
        # print('===均线值',self.ma[0])
        # print('===收盘价',self.datas[0].close[0])
        # print('===有订单在提交',self.order)
        #   如果订单在提交或者允许的情况下,直接返回
        if self.order:
            print('===有正在执行的订单', self.order)
            return
        # 空仓
        if not self.position.size:
            if self.datas[0].close[0] >= self.ma[0]:
                self.order = self.buy(size=200)
                print(f"====买入>>>买入价{self.datas[0].close[0]} > 均线价{self.ma[0]}  买入后仓位={self.getposition().size}")
        else:
            if self.datas[0].close[0] < self.ma[0]:
                self.order = self.sell(size=200)
                print(f"====卖出>>>买出价{self.datas[0].close[0]} < 均线价{self.ma[0]}  买入后仓位={self.getposition().size}")


if __name__ == '__main__':
    # code = '000001.SZ'
    code = '600519.SH'
    data = get_data(code, '20160101', '20200101')
    print(data.head())
    # print(data)

    '''第一步:数据加载 dataname:数据来源, fromdate:开始时间,enddate:结束时间(date格式)'''
    fromDate = datetime.date(2016, 1, 1)
    toDate = datetime.date(2020, 1, 1)
    data = bt.feeds.PandasData(dataname=data, fromdate=fromDate, todate=toDate)  # 加载数据

    '''第三步: 策略设置'''
    # 创建大脑
    cerebro = bt.Cerebro()
    # 添加策略
    cerebro.addstrategy(MyStrategy)
    # 将数据加入回测系统
    cerebro.adddata(data)
    # 设置经纪人
    startCash = 1000000
    cerebro.broker.setcash(startCash)
    cerebro.broker.setcommission(0.0002)
    # 运行大脑
    startDate = fromDate.strftime('%Y-%m-%d')
    endDate = toDate.strftime('%Y-%m-%d')
    print(f'初始资金:{round(startCash, 2)}\n回测时间:{startDate}{endDate}:')
    cerebro.run()
    endCash = cerebro.broker.getvalue()
    print(f'剩余总资金:{round(endCash, 2)}')
    netIncome = round(endCash - startCash, 2)
    print(f'净收益:{netIncome}')

    '''第四步,可视化'''
    # cerebro.plot(volume=False)
    cerebro.plot()


打印结果:

2019-12-18, BUY EXECUTED, Price: 1174.00, Cost: 234800.00, Comm 46.96
====卖出>>>买出价1157.4 < 均线价1157.716 买入后仓位=200
2019-12-20, SELL EXECUTED, Price: 1162.18, Cost: 234800.00, Comm 46.49
2019-12-20, OPERATION PROFIT, GROSS -2364.00, NET -2457.45
====买入>>>买入价1163.0 > 均线价1148.6955 买入后仓位=0
2019-12-30, BUY EXECUTED, Price: 1170.20, Cost: 234040.00, Comm 46.81
剩余总资金:1116412.06
净收益:116412.06

图表展示:
在这里插入图片描述

总结

先了解backtrader框架的基本组成部分,根据github文档例子,自己先写一遍代码,并跑通看看回测结果和图表视图,让自己能更快的认识backtrader,其中代码部分只需要认清执行的步骤顺序和代码结构方式就可以,具体的代码后面再逐一分析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Johnny2004

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值