Backtrader量化&回测10——取消预加载,读取自定义的可迭代数据

2023-11-18

从这一部分开始,我们将不会再聚焦于基本的操作细节上,而是更多的做一些有特点的修改(or 魔改)

这篇博客记录了:不进行预加载数据,而是实时加载数据的操作

各模块解释

import pandas as pd
import backtrader as bt
from loguru import logger
from datetime import datetime
from backtrader.feed import DataBase
from backtrader import date2num
import efinance

1. 获取K线数据

这是一个借助efinance模块获取历史行情数据的模块

def get_k_data(stock_code, begin: datetime, end: datetime) -> pd.DataFrame:
    """
    根据efinance工具包获取股票数据
    :param stock_code:股票代码
    :param begin: 开始日期
    :param end: 结束日期
    :return:
    """
    # stock_code = '600519'  # 股票代码,茅台
    k_dataframe: pd.DataFrame = efinance.stock.get_quote_history(
        stock_code, beg=begin.strftime("%Y%m%d"), end=end.strftime("%Y%m%d"))
    k_dataframe = k_dataframe.iloc[:, :9]
    k_dataframe.columns = ['name', 'code', 'date', 'open', 'close', 'high', 'low', 'volume', "turnover"]
    k_dataframe.index = pd.to_datetime(k_dataframe.date)
    k_dataframe.drop(['name', 'code', 'date'], axis=1, inplace=True)
    return k_dataframe

2. 可迭代数据类

class StockData(DataBase):
    """自定义数据格式"""
    params = (('turnover', -1),)
    lines = ('turnover',)

    def __init__(self, stock_code, stock_dataframe):
        self.dataname = stock_code
        self.stock_dataframe = stock_dataframe.sort_index()
        self.stock_iter = self.stock_dataframe.iterrows()

    def _load(self):  # 类似于策略的 next(),预期执行几次 next(),就会执行几次 _load()
        _series_datetime, _series_data = next(self.stock_iter, (None, {}))
        if _series_datetime is None:
            return False
        else:
            self.lines.datetime[0] = date2num(_series_datetime) # 注意这里的操作
            self.lines.open[0] = float(_series_data['open'])
            self.lines.high[0] = float(_series_data['high'])
            self.lines.low[0] = float(_series_data['low'])
            self.lines.close[0] = float(_series_data['close'])
            self.lines.volume[0] = int(_series_data['volume'])
            self.lines.turnover[0] = float(_series_data['turnover'])
            logger.debug("Load数据 {} TIME {} 收盘价 {}".format(self.dataname, _series_datetime, _series_data['close']))
            return True

这是一个可以加载【日期,开盘,最高,最低,收盘,持仓量,换手】的数据,其中:

在初始化的时候:

  • self.dataname:在策略中使用self.getdatabyname()时会与这个值对应
  • self.lines.close[0]:在策略中使用data.close[0]时会与这个值对应

其中时间部分注意需要使用date2num(),在_load(self)使用如下代码可以得到上一天的日期

datetime.fromordinal(int(self.datetime[-1])) # 只能解析成 date

或使用:

self.datetime.datetime(-1)

3. 策略模块

我们什么交易都不执行,只核对数据:

class TestStrategy(bt.Strategy):  # 策略
    def __init__(self):
        # 初始化交易指令、买卖价格和手续费
        total_bond_name = []
        for this_data in self.datas:
            if type(this_data).__name__ == "StockData":
                total_bond_name.append(this_data._name)
        self.total_bond_name = total_bond_name

    def next(self):  # 固定的函数,框架执行过程中会不断循环next(),过一个K线,执行一次next()
        # 此时调用 self.datas[0]即可查看当天的数据
        # 执行买入条件判断:当天收盘价格突破5日均线
        for bond_name in self.total_bond_name:
            print("{} {} 收盘价 {}".format(self.datetime.datetime(0), bond_name, self.getdatabyname(bond_name).close[0]))
        print()

示例代码

import pandas as pd
import backtrader as bt
from loguru import logger
from datetime import datetime
from backtrader.feed import DataBase
from backtrader import date2num
import efinance


def get_k_data(stock_code, begin: datetime, end: datetime) -> pd.DataFrame:
    """
    根据efinance工具包获取股票数据
    :param stock_code:股票代码
    :param begin: 开始日期
    :param end: 结束日期
    :return:
    """
    # stock_code = '600519'  # 股票代码,茅台
    k_dataframe: pd.DataFrame = efinance.stock.get_quote_history(
        stock_code, beg=begin.strftime("%Y%m%d"), end=end.strftime("%Y%m%d"))
    k_dataframe = k_dataframe.iloc[:, :9]
    k_dataframe.columns = ['name', 'code', 'date', 'open', 'close', 'high', 'low', 'volume', "turnover"]
    k_dataframe.index = pd.to_datetime(k_dataframe.date)
    k_dataframe.drop(['name', 'code', 'date'], axis=1, inplace=True)
    return k_dataframe


class TestStrategy(bt.Strategy):  # 策略
    def __init__(self):
        # 初始化交易指令、买卖价格和手续费
        total_bond_name = []
        for this_data in self.datas:
            if type(this_data).__name__ == "StockData":
                total_bond_name.append(this_data._name)
        self.total_bond_name = total_bond_name

    def next(self):  # 固定的函数,框架执行过程中会不断循环next(),过一个K线,执行一次next()
        # 此时调用 self.datas[0]即可查看当天的数据
        # 执行买入条件判断:当天收盘价格突破5日均线
        for bond_name in self.total_bond_name:
            print("{} {} 收盘价 {}".format(self.datetime.datetime(0), bond_name, self.getdatabyname(bond_name).close[0]))
        print()


class StockData(DataBase):
    """自定义数据格式"""
    params = (('turnover', -1),)
    lines = ('turnover',)

    def __init__(self, stock_code, stock_dataframe):
        self.dataname = stock_code
        self.stock_dataframe = stock_dataframe.sort_index()
        self.stock_iter = self.stock_dataframe.iterrows()

    def _load(self):  # 类似于策略的 next(),预期执行几次 next(),就会执行几次 _load()
        _series_datetime, _series_data = next(self.stock_iter, (None, {}))
        if _series_datetime is None:
            return False
        else:
            self.lines.datetime[0] = date2num(_series_datetime)
            self.lines.open[0] = float(_series_data['open'])
            self.lines.high[0] = float(_series_data['high'])
            self.lines.low[0] = float(_series_data['low'])
            self.lines.close[0] = float(_series_data['close'])
            self.lines.volume[0] = int(_series_data['volume'])
            self.lines.turnover[0] = float(_series_data['turnover'])
            logger.debug("Load数据 {} TIME {} 收盘价 {}".format(self.dataname, _series_datetime, _series_data['close']))
            return True


def load_stock_data(start_date: datetime, end_date: datetime):
    """加载股票数据"""
    data_dict = {}
    for stock_code in ["000636", "600519"]:
        data_dict[stock_code] = StockData(stock_code, get_k_data(stock_code, start_date, end_date))
    return data_dict


def main():
    start_date = datetime(2019, 1, 1)  # 起始日期
    end_date = datetime(2020, 1, 1)  # 终止日期
    initial_cash = 10000  # 设置启动资金: 1w
    commission = 1 / 1000  # 摩擦成本,买入、卖出均有摩擦成本
    # 数据源
    cerebral_system = bt.Cerebro()
    data_dict = load_stock_data(start_date, end_date)
    for key, value in data_dict.items():
        cerebral_system.adddata(value, name=key)
    cerebral_system.broker.setcash(initial_cash)  # 启动资金配置
    cerebral_system.broker.setcommission(commission=commission)  # 手续费
    logger.debug('初始资金: {} 回测期间:from {} to {}'.format(initial_cash, start_date, end_date))
    # =============== 运行回测系统 ==================
    logger.info("Run cerebral system")
    cerebral_system.addstrategy(TestStrategy)
    cerebral_system.run(preload=False)


if __name__ == '__main__':
    main()

得到的结果如下:

2022-12-01 14:44:35.485 | DEBUG    | __main__:main:98 - 初始资金: 10000 回测期间:from 2019-01-01 00:00:00 to 2020-01-01 00:00:00
2022-12-01 14:44:35.485 | INFO     | __main__:main:100 - Run cerebral system
2022-12-01 14:44:35.489 | DEBUG    | __main__:_load:74 - Load数据 000636 TIME 2019-01-02 00:00:00 收盘价 10.17
2022-12-01 14:44:35.490 | DEBUG    | __main__:_load:74 - Load数据 600519 TIME 2019-01-02 00:00:00 收盘价 526.45
2019-01-02 00:00:00 000636 收盘价 10.17
2019-01-02 00:00:00 600519 收盘价 526.45
2019-01-03 00:00:00 000636 收盘价 10.46
2019-01-03 00:00:00 600519 收盘价 517.47
2022-12-01 14:44:42.082 | DEBUG    | __main__:_load:74 - Load数据 000636 TIME 2019-01-03 00:00:00 收盘价 10.46
2022-12-01 14:44:42.082 | DEBUG    | __main__:_load:74 - Load数据 600519 TIME 2019-01-03 00:00:00 收盘价 517.47
2019-01-04 00:00:00 000636 收盘价 10.72
2019-01-04 00:00:00 600519 收盘价 529.47
2022-12-01 14:44:42.820 | DEBUG    | __main__:_load:74 - Load数据 000636 TIME 2019-01-04 00:00:00 收盘价 10.72
2022-12-01 14:44:42.821 | DEBUG    | __main__:_load:74 - Load数据 600519 TIME 2019-01-04 00:00:00 收盘价 529.47
2019-01-07 00:00:00 000636 收盘价 11.06
2019-01-07 00:00:00 600519 收盘价 532.96
2022-12-01 14:44:43.661 | DEBUG    | __main__:_load:74 - Load数据 000636 TIME 2019-01-07 00:00:00 收盘价 11.06
2022-12-01 14:44:43.662 | DEBUG    | __main__:_load:74 - Load数据 600519 TIME 2019-01-07 00:00:00 收盘价 532.96
2019-01-08 00:00:00 000636 收盘价 10.8
2019-01-08 00:00:00 600519 收盘价 532.26
2022-12-01 14:44:46.996 | DEBUG    | __main__:_load:74 - Load数据 000636 TIME 2019-01-08 00:00:00 收盘价 10.8
2022-12-01 14:44:46.997 | DEBUG    | __main__:_load:74 - Load数据 600519 TIME 2019-01-08 00:00:00 收盘价 532.26

数据是一致的,因此,我们可以可以在def _load()里添加任何我们想读取的数据,比如实时从数据库里获取

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Backtrader量化&回测10——取消预加载,读取自定义的可迭代数据 的相关文章

  • 最近的 AWS 区域的客户端 IP 地址

    Question 我想从客户端设备将一些数据上传到 AWS 但我想上传到最近的 AWS 区域的 S3 存储桶 同样 我希望能够从最近的区域下载 当然 我会在每个区域设置一个存储桶 我可以使用一个系统 它可以获取客户端的 IP 地址 然后确定
  • 指定的可执行文件不是该操作系统平台的有效应用程序。

    我不断收到错误消息System ComponentModel Win32Exception The specified executable is not a valid application for this OS platform 当
  • 使用 Tkinter 进行多线程 Python

    我用这些函数在画布上画小圆圈 这是绘制圆圈的函数 class Fourmis def init self can posx posy name radius self can can self largeur can int self ca
  • CodingBat sum67:为什么这个解决方案是错误的?

    我正在解决以下codingbat问题 返回数组中数字的总和 但忽略以 6 开头并延伸到下一个 7 的数字部分 每个 6 后面至少有一个 7 如果没有数字则返回 0 sum67 1 2 2 5 sum67 1 2 2 6 99 99 7 5
  • 如何在Redis中从hmset()切换到hset()?

    我收到弃用警告 即 Redis hmset 已弃用 请改用 Redis hset 但是 hset 采用第三个参数 我不知道是什么name应该是 info users 10 timestamp datetime utcnow strftime
  • 在 Django 中上传文件

    我在 Django 1 6 版本 中上传文件时遇到问题 当我尝试做的时候new file data save 在我的views py 中我收到此错误 quiz patent 22 medical record 2 exams 处的属性错误
  • Python Subversion 包装器库

    在颠覆的文档 http svnbook red bean com en 1 7 svn developer usingapi html svn developer usingapi otherlangs有一个从 Python 使用 Subv
  • set() 可以在 Python 进程之间共享吗?

    我正在 Python 2 7 中使用多重处理来处理非常大的数据集 当每个进程运行时 它会将整数添加到共享的 mp Manager Queue 中 但前提是其他进程尚未添加相同的整数 由于您无法对队列进行 in 式成员资格测试 因此我这样做的
  • cx_freeze:QODBC 驱动程序未加载

    我的 python 应用程序如下所示 test py from PyQt4 import QtCore from PyQt4 import QtGui from PyQt4 import QtSql import sys import at
  • 使用 gin 索引和 sqlalchemy 返回排名搜索结果

    我为全文搜索设置了 GIN 索引 我想获取与搜索查询匹配的记录列表 按排名排序 记录与搜索查询的匹配程度 对于结果 我只需要记录及其列 不需要用于排序的实际排名值 我有以下查询 它运行良好并从我的 postgresql 数据库返回预期结果
  • 使用 string.whitespace 删除 Python 中的空格

    Python 的 string whitespace 很棒 gt gt gt string whitespace t n x0b x0c r 如何在不手动输入 t n 等正则表达式的情况下将其与字符串一起使用 例如 它应该能够转动 请不要伤
  • 散景服务器获取鼠标位置

    我正在开发一个带有散景 0 12 2 的交互式应用程序 它根据特定的交互更新绘图 现在 我使用滑块来更改图中字形的位置 但实际上我想访问鼠标在特定图中的位置 数据集是一个多维矩阵 张量 密集数据 每个图在特定位置显示一个维度 如果我更改一个
  • 从 python 的单词列表中查找最长的常见单词序列

    我搜索了很多解决方案 确实发现了类似的问题 这个答案 https stackoverflow com questions 21930757 longest repeated substring返回可能不属于输入列表中所有字符串的最长字符序列
  • 如何判断Python对象是否是字符串?

    如何检查 Python 对象是否是字符串 常规字符串或 Unicode Python 2 Use isinstance obj basestring 对于要测试的对象obj Docs https docs python org 2 7 li
  • 如何在python中合并具有相同键的嵌套字典

    我有一个这样的数据结构 SNAPSHOT SnapshotVersion 304 SNAPSHOT SnapshotCreationDate 2015 06 21 17 33 41 CafeData CafeVersion 2807 Caf
  • 在Python中使用Counter()来构建直方图?

    我在另一个问题上看到我可以使用Counter 计算一组字符串中出现的次数 所以如果我有 A B A C A A I get Counter A 3 B 1 C 1 但现在 我如何使用该信息来构建直方图 对于您的数据 最好使用条形图而不是直方
  • 无法运行特定的 .pyc 文件

    使用编译在unix工作的python文件后 import py compile py compile compile server py 我在同一目录中获得 pyc 文件 但是当我尝试在 putty 中使用 server pyc 运行该文件
  • 在 Mac OS x 10.7.5 中运行 Scrapy 所需的文件,使用 Python 2.7.3 IEPD_free(32 位)

    我是第一次测试 scrapy 使用命令安装后 sudo easy install U scrapy 一切似乎都运行正常 但是 当我运行时 scrapy startproject tutorial 我得到以下信息 luismacbookpro
  • 如何从 Python 脚本捕获 Curl 的输出

    我想使用curl查找有关网页的信息 但在Python中 到目前为止我有这个 os system curl head www google com 如果我运行它 它会打印出 HTTP 1 1 200 OK Date Sun 15 Apr 20
  • 如何在Python中从stdin中逐行读取

    每个人都知道如何在 C 中计算 STDIN 中的字符 但是 当我尝试在 python3 中执行此操作时 我发现这是一个难题 计数器 py import sys chrCounter 0 for line in sys stdin readl

随机推荐

  • styled-components组件升级v4版本的全局样式踩坑

    注 本文使用ES6 Module模块化 框架选用React 最新版的 styled components v4 已经将原有的 injectGlobal 方法替换成了 createGlobalStyle 而且用法也和之前的 injectGlo
  • C++任意数字类型转 2进制、8进制、16进制

    C 任意数字类型转 2进制 8进制 16进制 平时我们在写程序的过程中会经常碰见进制转换的操作 偶尔写一次还好每次写 我们都又要重新定义函数进行转换 在这里博主就分享一下我自己编写的一个进制转换的方法吧 也比较通用 如没有耐心可以直接跳过思
  • 强化学习笔记3 回报和价值函数

    学习张斯俊和王树森两位大佬的专栏和课程后记的笔记 这篇笔记里面有一些个人理解 如有不对 欢迎大家指正 回报return 上一篇说过奖励reward 奖励是指当前状态S下 选择动作A 环境将会反馈回奖励R 我们利用R作为智能体学习的引导 希望
  • 【laravel5.6】The Process class relies on proc_open, which is not available on your PHP installation....

    部署服务器的时候 使用composer来安装依赖 遇到了 解决办法 在php ini中 找到disable functions选项 看看后面是否有proc open函数被禁用了 如果有的话 去掉即可 转载于 https www cnblog
  • Object.setPrototypeOf()

    Object setPrototypeOf 子对象 父对象 运行结束后 子对象 proto 指向 父对象 setPrototypeOf就是更换对象的 原型对象
  • 矩阵求导常用公式

    矩阵求导常用公式 1 引言 2 向量的导数 2 1 向量对标量求导 Vector by scalar 2 2 标量对向量求导 Scalar by vector 2 3 向量对向量求导 Vector by vector 3 矩阵的导数 3 1
  • 2022-05-14 Unity核心7——2D动画

    文章目录 一 序列帧动画 二 骨骼动画 2D Animation 三 反向动力学 IK 四 换装 五 骨骼动画 Spine 一 序列帧动画 一 什么是序列帧动画 我们最常见的序列帧动画就是我们看的日本动画片 以固定时间间隔按序列切换图片 就
  • 前端实现轮播图

    提示 实现轮播图效果有三种实现方式 一是通过纯css实现 二是通过jQuery实现 三是通过swiper插件实现 tips 可以用自己爱豆的图片 感觉简直不要太好 目录 前言 一 HTML部分 二 JS部分 提示 layer插件 盒子阴影
  • 机器学习或者机器视觉代码讲解视频教程

    当涉及到机器学习和机器视觉的代码讲解的视频教程时 以下是一些常见的在线教育平台和资源 提供了详细的代码讲解 Coursera https www coursera org Coursera上有一些知名的机器学习和计算机视觉课程 例如Andr
  • 小米手机上锁BL锁方法

    1 确保手机处于开发者模式 已打开USB调试 同时按住开机键 音量下键进入fastboot模式 使用usb数据线连接电脑 2 下载官方解锁工具miflash unlock xxxxxxxx zip 3 将miflash unlock xxx
  • NO.0 区块链,之我见前言

    区块链这个词 想必大家不会陌生 在如今爆炸式的信息时代 时不时的会在某个新闻推送 某个朋友圈分享 某个头条等直接或间接 主动或被动的有所耳闻 鉴于本人从事计算机软件开发方面职业的关系 时常会有一些朋友来问我一些关于区块链 比特币 ICO 交
  • 测试用例方法边界值

    测试用例方法边界值 什么是边界值方法 等价类重点是整体是否有效 边界值更多关注数值边界是否有效 边界值编写方法分析思路 1 找到符号产品需求的数值范围 2 确定有效的数值范围 3 根据有效的数值范围查找无效的数值范围 4 编写数值范围对应的
  • APK反编译之一:基础知识

    APK反编译之一 基础知识 本人接触不久 有错误望请各位神牛不吝赐教 仅仅希望把自己这段时间研究的东西分享一下 如果可以帮助到有需要的童鞋万感荣幸 欢迎评论转载 但请加上转载来源谢谢 请尊重开发者劳动成果 请勿用于非法用途 作者 lpohv
  • 自学Java没学历可以找到工作吗?

    除非技术真的diao 炸 天 否则大概率是找不到的 低学历能自学编程的人大有人在 你在搜索引擎上一查 低学历自学编程改变自身命运的不胜枚举 但无一不例外的 每个求学者的叙述都透漏着心酸 艰难困苦 披荆斩棘 这些词 说来容易 听来简单 但真正
  • ctfshow web由一道题的思路实现通杀

    ctfshow萌新计划 根据web1的几个解法思路我实现了对后面几道题的通杀 仔细想想感觉对于我这样的新手来说这几题还不错 题目一 web1 代码很安全 没有漏洞 打开题目很显然这一题考察的是代码审计 我们把代码粘贴下来审计一波
  • C#IList与List区别[转]

    首先IList 泛型接口是 ICollection 泛型接口的子代 并且是所有泛型列表的基接口 它仅仅是所有泛型类型的接口 并没有太多方法可以方便实用 如果仅仅是作为集合数据的承载体 确实 IList
  • pg_stat_statement如何安装部署使用

    pg stat statements模块提供一种跟踪执行统计服务器执行的所有SQL语句的手段 该模块默认是不开启的 如果需要开启需要我们手动对其进进行编译安装 修改配置文件并重启数据库 并在使用前手动载入该模块 1 手动对pg stat s
  • 离线强化学习(Offline RL)系列3: (算法篇)策略约束-BCQ算法详解与实现

    更新日志 论文信息 Off Policy Deep Reinforcement Learning without Exploration Github 本文主要介绍的是连续空间状态下的策略约束的BCQ算法 作者首先就offline RL中容
  • 软件质量属性

    质量特性 质量子特性 功能性 适宜性 准确性 互用性 依从性 安全性 可靠性 成熟型 容错性 可恢复性 可用性 可理解性 易学性 可操作性 效率 时间特性 资源特性 可维护性 可分析性 可修改性 稳定性 可测试性 可移植性 适应性 易安装性
  • Backtrader量化&回测10——取消预加载,读取自定义的可迭代数据

    文章目录 各模块解释 1 获取K线数据 2 可迭代数据类 3 策略模块 示例代码 从这一部分开始 我们将不会再聚焦于基本的操作细节上 而是更多的做一些有特点的修改 or 魔改 这篇博客记录了 不进行预加载数据 而是实时加载数据的操作 各模块