【python量化交易】qteasy使用教程07——创建更加复杂的自定义交易策略

创建更加复杂的自定义交易策略

  • 使用交易策略类,创建更复杂的自定义策略
    • 开始前的准备工作
    • 本节的目标
    • 继承Strategy类,创建一个复杂的多因子选股策略
      • 策略和回测参数配置,并开始回测
    • 本节回顾

使用交易策略类,创建更复杂的自定义策略

qteasy是一个完全本地化部署和运行的量化交易分析工具包,Github地址在这里,并且可以通过pip安装:

$ pip install qteasy -U

qteasy具备以下功能:

  • 金融数据的获取、清洗、存储以及处理、可视化、使用
  • 量化交易策略的创建,并提供大量内置基本交易策略
  • 向量化的高速交易策略回测及交易结果评价
  • 交易策略参数的优化以及评价
  • 交易策略的部署、实盘运行

通过本系列教程,您将会通过一系列的实际示例,充分了解qteasy的主要功能以及使用方法。

开始前的准备工作

在开始本节教程前,请先确保您已经掌握了下面的内容:

  • 安装、配置qteasy —— QTEASY教程1
  • 设置了一个本地数据源,并已经将足够的历史数据下载到本地——QTEASY教程2
  • 学会创建交易员对象,使用内置交易策略,——QTEASY教程3
  • 学会使用混合器,将多个简单策略混合成较为复杂的交易策略——QTEASY教程4
  • 了解自定策略的基础——QTEASY教程5 ,QTEASY教程6

在QTEASY文档中,还能找到更多关于使用内置交易策略、创建自定义策略等等相关内容。对qteasy的基本使用方法还不熟悉的同学,可以移步那里查看更多详细说明。

qteasy的内核被设计为一个兼顾高速执行以及足够的灵活性的框架,理论上您可以实现您所设想的任何类型的交易策略。

同时,qteasy的回测框架也做了相当多的特殊设计,可以完全避免您无意中在交易策略中导入"未来函数",确保您的交易策略在回测时完全基于过去的数据,同时也使用了很多预处理技术以及JIT技术对内核关键函数进行了编译,以实现不亚于C语言的运行速度。

不过,为了实现理论上无限可能的交易策略,仅仅使用内置交易策略以及策略混合就不一定够用了,一些特定的交易策略,或者一些特别复杂的交易策略是无法通过内置策略混合而成的,这就需要我们使用qteasy提供的Strategy基类,基于一定的规则创建一个自定义交易策略了。

本节的目标

在本节中,我们将介绍qteasy的交易策略基类,通过一个具体的例子详细讲解如何基于这几个基类,创建一个只属于您自己的交易策略。为了说明

继承Strategy类,创建一个复杂的多因子选股策略

在这个例子中,我们使用

import qteasy as qt
import numpy as np

def market_value_weighted(stock_return, mv, mv_cat, bp_cat, mv_target, bp_target):
    """ 根据mv_target和bp_target计算市值加权收益率,在策略中调用此函数计算加权收益率

    """
    sel = (mv_cat == mv_target) & (bp_cat == bp_target)
    mv_total = np.nansum(mv[sel])
    mv_weight = mv / mv_total
    return_total = np.nansum(stock_return[sel] * mv_weight[sel])
    return return_total


class MultiFactors(qt.FactorSorter):
    """ 开始定义交易策略
    """
    def __init__(self, pars: tuple = (0.5, 0.3, 0.7)):
    	"""交易策略的初始化参数"""
        super().__init__(
                pars=pars,  
                par_count=3,  # 策略的可调参数有三个
                par_types=['float', 'float', 'float'],  # 参数1:大小市值分类界限,参数2:小/中bp分界线,参数3,中/大bp分界线
                par_range=[(0.01, 0.99), (0.01, 0.49), (0.50, 0.99)],
                name='MultiFactor',
                description='根据Fama-French三因子回归模型估算HS300成分股的alpha值选股',
                strategy_run_timing='close',  # 在周期结束(收盘)时运行
                strategy_run_freq='m',  # 每月执行一次选股(每周或每天都可以)
                strategy_data_types='pb, total_mv, close',  # 执行选股需要用到的股票数据
                data_freq='d',  # 数据频率(包括股票数据和参考数据)
                window_length=20,  # 回测时的视窗长度为20天
                use_latest_data_cycle=True,  # 设置使用最新的数据
                reference_data_types='close-000300.SH',  # 选股需要用到市场收益率,使用沪深300指数的收盘价计算,因此设置HS300指数的收盘价作为参考数据传入
                max_sel_count=10,  # 最多选出10支股票
                sort_ascending=True,  # 选择因子最小的股票
                condition='less',  # 仅选择因子小于某个值的股票
                lbound=0,  # 仅选择因子小于0的股票
                ubound=0,  # 仅选择因子小于0的股票 
        )
    
    def realize(self, h, **kwargs):
		""" 策略的选股逻辑在realize()函数中定义
		"""
        size_gate_percentile, bp_small_percentile, bp_large_percentile = self.pars
        # 读取投资组合的数据PB和total_MV的最新值
        pb = h[:, -1, 0]  # 当前所有股票的PB值
        mv = h[:, -1, 1]  # 当前所有股票的市值
        pre_close = h[:, -2, 2]  # 当前所有股票的前收盘价
        close = h[:, -1, 2]  # 当前所有股票的最新收盘价

        # 读取参考数据(r)
        market_pre_close = r[-2, 0]  # HS300的昨收价
        market_close = r[-1, 0]  # HS300的收盘价

        # 计算账面市值比,为pb的倒数
        bp = pb ** -1
        # 计算市值的50%的分位点,用于后面的分类
        size_gate = np.nanquantile(mv, size_gate_percentile)
        # 计算账面市值比的30%和70%分位点,用于后面的分类
        bm_30_gate = np.nanquantile(bp, bp_small_percentile)
        bm_70_gate = np.nanquantile(bp, bp_large_percentile)
        # 计算每只股票的当日收益率
        stock_return = pre_close / close - 1

        # 根据每只股票的账面市值比和市值,给它们分配bp分类和mv分类
        # 市值小于size_gate的cat为1,否则为2
        mv_cat = np.ones_like(mv)
        mv_cat += (mv > size_gate).astype('float')
        # bp小于30%的cat为1,30%~70%之间为2,大于70%为3
        bp_cat = np.ones_like(bp)
        bp_cat += (bp > bm_30_gate).astype('float')
        bp_cat += (bp > bm_70_gate).astype('float')

        # 获取小市值组合的市值加权组合收益率
        smb_s = (market_value_weighted(stock_return, mv, mv_cat, bp_cat, 1, 1) +
                 market_value_weighted(stock_return, mv, mv_cat, bp_cat, 1, 2) +
                 market_value_weighted(stock_return, mv, mv_cat, bp_cat, 1, 3)) / 3
        # 获取大市值组合的市值加权组合收益率
        smb_b = (market_value_weighted(stock_return, mv, mv_cat, bp_cat, 2, 1) +
                 market_value_weighted(stock_return, mv, mv_cat, bp_cat, 2, 2) +
                 market_value_weighted(stock_return, mv, mv_cat, bp_cat, 2, 3)) / 3
        smb = smb_s - smb_b
        # 获取大账面市值比组合的市值加权组合收益率
        hml_b = (market_value_weighted(stock_return, mv, mv_cat, bp_cat, 1, 3) +
                 market_value_weighted(stock_return, mv, mv_cat, bp_cat, 2, 3)) / 2
        # 获取小账面市值比组合的市值加权组合收益率
        hml_s = (market_value_weighted(stock_return, mv, mv_cat, bp_cat, 1, 1) +
                 market_value_weighted(stock_return, mv, mv_cat, bp_cat, 2, 1)) / 2
        hml = hml_b - hml_s

        # 计算市场收益率
        market_return = market_pre_close / market_close - 1

        coff_pool = []
        # 对每只股票进行回归获取其alpha值
        for rtn in stock_return:
            x = np.array([[market_return, smb, hml, 1.0]])
            y = np.array([[rtn]])
            # OLS估计系数
            coff = np.linalg.lstsq(x, y)[0][3][0]
            coff_pool.append(coff)

        # 以alpha值为股票组合的选股因子执行选股
        factors = np.array(coff_pool)

        return factors

策略和回测参数配置,并开始回测

定义好上面的策略之后,就可以开始进行回测了,我们需要在qteasy中创建一个交易员对象,操作前面创建的策略:

shares = qt.filter_stock_codes(index='000300.SH', date='20190501')  # 选择股票池,包括2019年5月以来所有沪深300指数成分股
# 设置回测的运行参数
qt.config(mode=1,  # mode=1表示回测模式
       invest_start='20160405',  # 回测开始日期
       invest_end='20210201',  # 回测结束日期
       asset_type='E',  # 投资品种为股票
       asset_pool=shares,  # shares包含同期沪深300指数的成份股
       trade_batch_size=100,  # 买入批量为100股
       sell_batch_size=1,  # 卖出批量为整数股
       trade_log=True,  # 生成交易记录
       )
       
#  开始策略的回测

alpha = MultiFactors()  # 生成一个交易策略的实例,名为alpha
op = qt.Operator(alpha, signal_type='PT')  # 生成交易员对象,操作alpha策略,交易信号的类型为‘PT',意思是生成的信号代表持仓比例,例如1代表100%持有股票,0.35表示持有股票占资产的35%
op.op_type = 'stepwise'  # 运行模式为步进模式
op.set_blender('1.0*s0', "close")  # 交易策略混合方式,只有一个策略,不需要混合
op.run()  # 开始运行

在这里插入图片描述

本节回顾

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

(四十)第 6 章 树和二叉树(树的双亲表存储)

1. 背景说明 2. 示例代码 1) errorRecord.h // 记录错误宏定义头文件#ifndef ERROR_RECORD_H #define ERROR_RECORD_H#include <stdio.h> #include <string.h> #include <stdint.h>// 从文件路径中提取文件名 #define FILE_NAME(X) strrchr(X, \\) ? strrch…

基于yolov5+streamlit目标检测演示系统设计

YOLOv5与Streamlit&#xff1a;智能目标检测可视化展示介绍 随着人工智能技术的飞速发展&#xff0c;目标检测技术已成为推动智能化社会进步的关键技术之一。在众多目标检测算法中&#xff0c;YOLOv5以其卓越的性能和实时性&#xff0c;成为了业界的佼佼者。与此同时&#xff…

代码随想录阅读笔记-动态规划【爬楼梯】

题目 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 注意&#xff1a;给定 n 是一个正整数。 示例 1&#xff1a; 输入&#xff1a; 2输出&#xff1a; 2解释&#xff1a; 有两种方法可以爬到楼…

[AutoSar]BSW_Diagnostic_002 DCM模块介绍

目录 关键词平台说明背景一、DCM所处架构位置二、DCM 与其他模块的交互三、DCM 的功能四、DCM的内部子模块4.1 Diagnostic Session Layer (DSL)4.1 DSL 与其他模块的交互 4.2 Diagnostic Service Dispatcher (DSD)4.3 Diagnostic Service Processing (DSP)4.4 小结 关键词 嵌入…

vue3土味情话pinia可以持久保存再次修改App样式

我是不是你最疼爱的人-失去爱的城市 <template><div class"talk"><button click"getLoveTalk">土味情话</button><ul><li v-for"talk in talkStore.talkList" :key"talk.id">{{ talk.title }}<…

计算机服务器中了360后缀勒索病毒怎么解密,360后缀勒索病毒恢复

计算机网络技术的不断发展与应用&#xff0c;为企业的生产运营提供了极大便利&#xff0c;大大提高了企业的办公效率&#xff0c;为企业的生产运营注入了新的动力&#xff0c;但网络是一把双刃剑&#xff0c;在为企业提供便利的同时&#xff0c;也为企业的数据安全带来严重威胁…

macos使用yarn创建vite时出现Usage Error: The nearest package directory问题

步骤是macos上使用了yarn create vite在window上是直接可以使用了yarn但是在macos上就出现报错 我们仔细看&#xff0c;它说的If /Users/chentianyu isnt intended to be a project, remove any yarn.lock and/or package.json file there.说是要我们清除yarn.lock和package.js…

深圳晶彩智能ESP32-1732S019实时观看GPIO的状态

深圳晶彩智能ESP32-1732S019介绍 ESP32-1732S019开发板是基于ESP32-S3-WROOM-1模块作为主控&#xff0c;双核MCU ,集成WI-FI和蓝牙功能&#xff0c;主控频率可达240MHz , 512KB SRAM , 384KB ROM&#xff0c;8M PSRAM&#xff0c;16MB Flash&#xff0c;显示分辨率为170*320 I…

职校智慧校园现状及问题分析

各大中职院校及高职院校是校园信息化的先行者和开拓者&#xff0c;很早就开始注重信息化基础设施建设和信息化人文素养的提升。在过去几年里&#xff0c;随着国家大力发展与扶植职校教育&#xff0c;学校投入相当的经费进行了校园信息通信网络、计算机等基础硬件设备建设&#…

单调栈问题

原理 单调栈的核心原理是&#xff1a;在栈内保持元素的单调性&#xff08;递增或递减&#xff09; 单调递增栈&#xff1a; 用于处理“下一个更小的元素”问题。当新元素比栈顶元素小或等于时&#xff0c;直接入栈&#xff1b;否则&#xff0c;一直从栈顶弹出元素&#xff0c…

AtCoder Regular Contest 177 D. Earthquakes(概率 单调栈)

题目 D - Earthquakes 思路来源 官方题解 题解 对于不存在连锁反应的区间&#xff0c;每个区间独立处理&#xff0c;最后求个乘积 对于每个区间&#xff0c;相邻的两个杆子距离都小于H&#xff0c; 意味着没倒的区间是个连续的区间&#xff0c;假设要算i的概率 一定是第i…

金三银四面试题(二十七):适配器模式知多少?

什么是适配器模式 适配器模式&#xff08;Adapter Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许将一个类的接口转换为客户期望的另一个接口。通过适配器&#xff0c;原本不兼容的接口可以一起工作&#xff0c;从而提高系统的灵活性和可扩展性。 关键元素&…

JVM 类的加载器

文章目录 1. 作用2. 类加载器的显示加载与隐式加载3. 类加载机制的必要性4. 加载的类是唯一的吗5. 类加加载机制的基本特征(了解) 1. 作用 类加载器是 JVM 执行类加载机制的前提。 ClassLoader 的作用&#xff1a; ClassLoader 是 Java 的核心组件&#xff0c;所有的 Class 都…

C++基础与深度解析 | C++初探 | Hello World | 系统I/O | 控制流 | 结构体与自定义数据类型

文章目录 一、从Hello World谈起二、系统I/O三、控制流四、结构体与自定义数据类型 一、从Hello World谈起 #include <iostream>void fun(const char *pInfo) {std::cout << pInfo << std::endl; }int main() {fun("Hello World!");fun("Hel…

【补充】图神经网络前传——DeepWalk

论文阅读 论文&#xff1a;https://arxiv.org/pdf/1403.6652 参考&#xff1a;【论文逐句精读】DeepWalk&#xff0c;随机游走实现图向量嵌入&#xff0c;自然语言处理与图的首次融合_随机游走图嵌入-CSDN博客 abstract DeepWalk是干什么的&#xff1a;在一个网络中学习顶点…

求最大梯形的面积

【入门】求最大梯形的面积 今天做4星题单发现一个好玩的&#xff08;太简单了&#xff09;。 说明 从键盘读入n(3<n<100)个梯形的上底、下底和高&#xff0c;请问这n个梯形中&#xff0c;最大面积的梯形的面积是多少&#xff1f;&#xff08;梯形面积的求解公式为 S …

ExcelVBA在选择区域(有合并)中删除清除空行

【问题】 关于删除空行&#xff0c;以前是用函数来完成工作的&#xff0c; 今天有人提出问题&#xff0c;传来这个文件&#xff0c; 现有数据&#xff0c;1w多行&#xff0c;其中有部分列有不同合并单元格&#xff0c;跨行也不一样。如果要进行筛选删除空行&#xff0c;有一定的…

Rerank进一步提升RAG效果

RAG & Rerank 目前大模型应用中&#xff0c;RAG&#xff08;Retrieval Augmented Generation&#xff0c;检索增强生成&#xff09;是一种在对话&#xff08;QA&#xff09;场景下最主要的应用形式&#xff0c;它主要解决大模型的知识存储和更新问题。 简述RAG without R…

买卖股票的最佳时机 II(LeetCode 122)

❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容&#xff0c;和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣&#xff01; 推荐&#xff1a;数据分析螺丝钉的首页 格物致知 终身学习 期待您的关注 导航&#xff1a; LeetCode解锁100…

整体安全设计

人员和资产的安全是当今许多组织的最高优先事项之一。随着暴力事件在美国各地盛行——枪击事件、袭击、内乱等——建筑物业主必须为其建筑物及其居住者的安全做好计划。 为了创造一个安全的环境&#xff0c;新设施或园区的安全设计必须超越基本的摄像头和访问控制设备&#xf…