量化交易 - 聚宽joinquant - 多因子入门研究 - 源码开源

news2025/4/15 19:41:11

先看一下我们的收益: JoinQuant直达这里看看

 下面讲解原理和代码。

目录

一、是否为st

二、是否停牌

三、市值小、roe大

四、编写回测代码


今天来研究一下多因子回测模型,这里以‘市值’、‘roe’作为例子。

几个标准:沪深300里选股,市值小、roe大、排出st 停牌、定期调仓

一、是否为st

# 是否st
is_st_info = get_extras('is_st', ['000001.XSHE', '000018.XSHE'], start_date='2025-04-01', end_date='2025-04-10', df=True)
print(is_st_info)
            000001.XSHE  000018.XSHE
2025-04-01        False         True
2025-04-02        False         True
2025-04-03        False         True
2025-04-07        False         True
2025-04-08        False         True
2025-04-09        False         True
2025-04-10        False         True

然后我们改装成为函数

# 获取st股票
def get_st_stocks(stock_list, end_date, count):
    is_st_info = get_extras('is_st', stock_list, end_date=end_date, count=count, df=True)
    st_stocks = []
    for stock in stock_list:
        if is_st_info[stock].any():  # 检查该股票是否在任何一天为True
            st_stocks.append(stock)
    return st_stocks

x = get_st_stocks(['300956.XSHE', '300542.XSHE', '000018.XSHE'], end_date='2025-04-12', count=5)
print(x)

二、是否停牌

# 是否停牌
x = get_price(['300956.XSHE', '300542.XSHE'], count=5, end_date='2025-04-12', 
              fields='paused',
              frequency='daily', skip_paused=False, panel=False)
print(x)
        time         code  paused
0 2025-04-07  300956.XSHE     0.0
1 2025-04-08  300956.XSHE     0.0
2 2025-04-09  300956.XSHE     0.0
3 2025-04-10  300956.XSHE     1.0
4 2025-04-11  300956.XSHE     1.0
5 2025-04-07  300542.XSHE     0.0
6 2025-04-08  300542.XSHE     1.0
7 2025-04-09  300542.XSHE     1.0
8 2025-04-10  300542.XSHE     1.0
9 2025-04-11  300542.XSHE     1.0

同样,我们改装成函数

# 是否停牌
def get_paused_stocks(stock_list, end_date, count):
    paused_info = get_price(stock_list, count=count, end_date=end_date, 
                            fields='paused', frequency='daily', 
                            skip_paused=False, panel=False)
    paused_stocks = []
    for stock in stock_list:
        if (paused_info[paused_info['code'] == stock]['paused'] == 1.0).any():  # 检查该股票是否在任何一天为1.0
            paused_stocks.append(stock)
    return paused_stocks

x = get_paused_stocks(['000001.XSHE', '300956.XSHE', '300542.XSHE'], end_date='2025-04-12', count=5)
print(x)

 

三、市值小、roe大

获取某一天沪深300股票中yb天不停牌、不st,且满足市值和ROE排名前N的股票

from jqdata import *

def get_mystocks(date, yb=63, N=20):
    """
    获取某一天沪深300股票中yb天不停牌、不st,且满足市值和ROE排名前N的股票

    :param date: 指定日期
    :param yb: 多少天不停牌
    :param N: 排名前多少
    :return: 满足条件的股票代码列表
    """
    # 获取沪深300的成分股
    hs300_stocks = get_index_stocks('000300.XSHG', date=date)

    # 获取股票的基本面数据
    q = query(
        valuation.code,
        valuation.market_cap,
        indicator.roe
    ).filter(
        valuation.code.in_(hs300_stocks)
    )
    df = get_fundamentals(q, date=date)
    #print(df.head())

    # 获取停牌股票
    paused_stocks = get_paused_stocks(hs300_stocks, end_date=date, count=yb)
    #print(paused_stocks)
    
    # 获取st股票
    st_stocks = get_st_stocks(hs300_stocks, end_date=date, count=yb)
    #print(st_stocks)

    # 获取剔除停牌和ST的股票代码列表
    all_paused_stocks = set(paused_stocks + st_stocks)

    # 从df中筛选出剔除停牌和ST的股票
    df = df[~df['code'].isin(all_paused_stocks)]

    # 对市值进行升序排名,对ROE进行降序排名
    df['market_cap_rank'] = df['market_cap'].rank(method='first', ascending=True)
    df['roe_rank'] = df['roe'].rank(method='first', ascending=False)
    df['composite_rank'] = df['market_cap_rank'] + df['roe_rank']

    # 按综合排名升序排序并选取前N
    df_sorted = df.sort_values(by='composite_rank', ascending=True).head(N)

    # 提取股票代码并返回
    mystocks = df_sorted['code'].tolist()
    return mystocks

mystocks = get_mystocks('2024-12-31')
print(mystocks)
['300628.XSHE', '002555.XSHE', '000876.XSHE', '300394.XSHE', '603833.XSHG', '605117.XSHG', '300316.XSHE', '000975.XSHE', '000661.XSHE', '002007.XSHE', '601021.XSHG', '601799.XSHG', '300896.XSHE', '688082.XSHG', '000807.XSHE', '000408.XSHE', '300832.XSHE', '600570.XSHG', '002920.XSHE', '600066.XSHG']

 

四、编写回测代码

# 导入函数库
from jqdata import *
import datetime
import numpy as np

# 策略初始化
def initialize(context):
    set_benchmark('000300.XSHG')
    set_option('use_real_price', True)
    log.set_level('order', 'error')
    set_order_cost(OrderCost(close_tax=0, open_commission=0, close_commission=0, min_commission=0), type='stock')
    
    g.t = 0
    g.tc = 15  # 调仓频率
    g.yb = 63  # 样本长度
    g.N = 20   # 持仓数量
    run_daily(market_open, time='open', reference_security='000300.XSHG')


def market_open(context):
    now = context.current_dt
    before_1d_time = now - timedelta(days=1)
    end_date = before_1d_time.strftime("%Y-%m-%d")
    
    if g.t % g.tc == 0:
        mystocks = get_mystocks(end_date, g.yb, g.N)
        rebalance_position(context, mystocks)
    
    g.t += 1


# 获取st股票
def get_st_stocks(stock_list, end_date, count):
    is_st_info = get_extras('is_st', stock_list, end_date=end_date, count=count, df=True)
    st_stocks = []
    for stock in stock_list:
        if is_st_info[stock].any():  # 检查该股票是否在任何一天为True
            st_stocks.append(stock)
    return st_stocks
    
# 是否停牌
def get_paused_stocks(stock_list, end_date, count):
    paused_info = get_price(stock_list, count=count, end_date=end_date, 
                            fields='paused', frequency='daily', 
                            skip_paused=False, panel=False)
    paused_stocks = []
    for stock in stock_list:
        if (paused_info[paused_info['code'] == stock]['paused'] == 1.0).any():  # 检查该股票是否在任何一天为1.0
            paused_stocks.append(stock)
    return paused_stocks
    

def get_mystocks(date, yb=63, N=20):
    """
    获取某一天沪深300股票中yb天不停牌,且满足市值和ROE排名前N的股票

    :param date: 指定日期
    :param yb: 多少天不停牌
    :param N: 排名前多少
    :return: 满足条件的股票代码列表
    """
    # 获取沪深300的成分股
    hs300_stocks = get_index_stocks('000300.XSHG', date=date)

    # 获取股票的基本面数据
    q = query(
        valuation.code,
        valuation.market_cap,
        indicator.roe
    ).filter(
        valuation.code.in_(hs300_stocks)
    )
    df = get_fundamentals(q, date=date)
    #print(df.head())

    # 获取停牌股票
    paused_stocks = get_paused_stocks(hs300_stocks, end_date=date, count=yb)
    #print(paused_stocks)
    
    # 获取st股票
    st_stocks = get_st_stocks(hs300_stocks, end_date=date, count=yb)
    #print(st_stocks)

    # 获取剔除停牌和ST的股票代码列表
    all_paused_stocks = set(paused_stocks + st_stocks)

    # 从df中筛选出剔除停牌和ST的股票
    df = df[~df['code'].isin(all_paused_stocks)]

    # 对市值进行升序排名,对ROE进行降序排名
    df['market_cap_rank'] = df['market_cap'].rank(method='first', ascending=True)
    df['roe_rank'] = df['roe'].rank(method='first', ascending=False)
    df['composite_rank'] = df['market_cap_rank'] + df['roe_rank']

    # 按综合排名升序排序并选取前N
    df_sorted = df.sort_values(by='composite_rank', ascending=True).head(N)

    # 提取股票代码并返回
    mystocks = df_sorted['code'].tolist()
    return mystocks

"""
###################### 工具 ######################

调仓:
先卖出持仓中不在 stock_list 中的股票
再等价值买入 stock_list 中的股票
"""
def rebalance_position(context, stock_list):
    current_holding = context.portfolio.positions.keys()
    stocks_to_sell = list(set(current_holding) - set(stock_list))
    # 卖出
    bulk_orders(stocks_to_sell, 0)
    total_value = context.portfolio.total_value

    # 买入
    bulk_orders(stock_list, total_value/len(stock_list))

# 批量买卖股票
def bulk_orders(stock_list,target_value):
    for i in stock_list:
        order_target_value(i, target_value)

上面就是所有的源码了。

参考:这里

原文太老了,代码也比较繁琐,故简化很多。

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

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

相关文章

FPGA 37 ,FPGA千兆以太网设计实战:RGMII接口时序实现全解析( RGMII接口时序设计,RGMII~GMII,GMII~RGMII 接口转换 )

目录 前言 一、设计流程 1.1 需求理解 1.2 模块划分 1.3 测试验证 二、模块分工 2.1 RGMII→GMII(接收方向,rgmii_rx 模块) 2.2 GMII→RGMII(发送方向,rgmii_tx 模块) 三、代码实现 3.1 顶层模块 …

上篇:《排序算法的奇妙世界:如何让数据井然有序?》

个人主页:strive-debug 排序算法精讲:从理论到实践 一、排序概念及应用 1.1 基本概念 **排序**:将一组记录按照特定关键字(如数值大小)进行递增或递减排列的操作。 1.2 常见排序算法分类 - **简单低效型**&#xff…

红宝书第三十四讲:零基础学会单元测试框架:Jest、Mocha、QUnit

红宝书第三十四讲:零基础学会单元测试框架:Jest、Mocha、QUnit 资料取自《JavaScript高级程序设计(第5版)》。 查看总目录:红宝书学习大纲 一、单元测试是什么? 就像给代码做“体检”,帮你检查…

CST1019.基于Spring Boot+Vue智能洗车管理系统

计算机/JAVA毕业设计 【CST1019.基于Spring BootVue智能洗车管理系统】 【项目介绍】 智能洗车管理系统,基于 Spring Boot Vue 实现,功能丰富、界面精美 【业务模块】 系统共有三类用户,分别是:管理员用户、普通用户、工人用户&…

HTTP:五.WEB服务器

web服务器 定义:实现提供资源或应答的提供者都可以谓之为服务器!web服务器工作内容 接受建立连接请求 接受请求 处理请求 访问报文中指定的资源 构建响应 发送响应 记录事务处理过程 Web应用开发用到的一般技术元素 静态元素:html, img,js,Css,SWF,MP4 动态元素:PHP,…

0基础 | 硬件滤波 C、RC、LC、π型

一、滤波概念 (一)滤波定义 滤波是将信号中特定波段频率滤除的操作,是抑制和防止干扰的重要措施。通过滤波器实现对特定频率成分的筛选,确保目标信号的纯净度,提升系统稳定性。 (二)滤波器分…

图论基础理论

在我看来,想要掌握图的基础应用,仅需要三步走。 什么是图(基本概念)、图的构造(打地基)、图的遍历方式(应用的基础) 只要能OK的掌握这三步、就算图论入门了!&#xff0…

企业级低代码平台的架构范式转型研究

在快速迭代的数字时代,低代码平台如同一股清流,悄然成为开发者们的新宠。 它利用直观易用的拖拽式界面和丰富的预制组件,将应用程序的开发过程简化到了前所未有的程度。通过封装复杂的编程逻辑和提供强大的集成能力,低代码平台让…

怎么免费下载GLTF/GLB格式模型文件,还可以在线编辑修改

​ 现在非常流行glb格式模型,和gltf格式文件,可是之类模型网站非常非常少 1,咱们先直接打开http://glbxz.com 官方glb下载网站 glbxz.com 2 可以搜索,自己想要的模型关键词 3,到自己想下载素材页面 4,…

大模型到底是怎么产生的?一文揭秘大模型诞生全过程

前言 大模型到底是怎么产生的呢? 本文将从最基础的概念开始,逐步深入,用通俗易懂的语言为大家揭开大模型的神秘面纱。 大家好,我是大 F,深耕AI算法十余年,互联网大厂核心技术岗。 知行合一,不写水文,喜欢可关注,分享AI算法干货、技术心得。 【专栏介绍】: 欢迎关注《…

2025年3月 Scratch图形化三级 真题解析 中国电子学会全国青少年软件编程等级考试

2025年3月Scratch图形化编程等级考试三级真题试卷 一、选择题 第 1 题 默认小猫角色,scratch运行程序后,下列说法正确的是?( ) A.小猫的颜色、位置在一直变化 B.小猫在舞台中的位置在一直变化,颜色…

【贪心之摆动序列】

题目: 分析: 这里我们使用题目中给的第二个实例来进行分析 题目中要求我们序列当中有多少个摆动序列,摆动序列满足一上一下,一下一上,这样是摆动序列,并且要输出摆动序列的最长长度 通过上面的图我们可以…

0x25广度优先搜索+0x26广搜变形

1.一般bfs AcWing 172. 立体推箱子 #include<bits/stdc.h> using namespace std; int n,m; char s[505][505]; int vis[3][505][505]; int df[3][4]{{1,1, 2,2},{0,0,1,1}, {0,0,2,2}}; int dx[3][4]{{0,0,1,-2},{0,0,1,-1},{2,-1,0,0}}; int dy[3][4]{{1,-2,0,0},{2,…

java面向对象02:回顾方法

回顾方法及加深 定义方法 修饰符 返回类型 break&#xff1a;跳出switch和return的区别 方法名 参数列表 package com.oop.demo01;//Demo01类 public class Demo01 {//main方法public static void main(String[] args) {}/*修饰符 返回值类型 方法名(...){//方法体return…

数据结构day05

一 栈的应用&#xff08;括号匹配&#xff09; 各位同学大家好&#xff0c;在之前的小结中&#xff0c;我们学习了栈和队列这两种数据结构&#xff0c;那从这个小节开始&#xff0c;我们要学习几种栈和队列的典型应用。这个小节中&#xff0c;我们来看一下括号匹配问题&#xf…

windows中搭建Ubuntu子系统

windows中搭建虚拟环境 1.配置2.windows中搭建Ubuntu子系统2.1windows配置2.1.1 确认启用私有化2.1.2 将wsl2设置为默认版本2.1.3 确认开启相关配置2.1.4重启windows以加载更改配置 2.2 搭建Ubuntu子系统2.2.1 下载Ubuntu2.2.2 迁移位置 3.Ubuntu子系统搭建docker环境3.1安装do…

ImgTool_0.8.0:图片漂白去底处理优化工具

ImgTool_0.8.0 是一款专为Windows设计的‌免费、绿色便携式图片处理工具‌&#xff0c;支持 Windows 7/8/10/11 系统‌。其核心功能为‌漂白去底‌&#xff0c;可高效去除扫描件或手机拍摄图片中的泛黄、灰底及阴影&#xff0c;同时提供智能纠偏、透视校正等辅助功能&#xff0…

BGP路由协议之对等体

IGP 可以通过组播报文发现直连链路上的邻居&#xff0c;而 BGP 是通过 TCP&#xff1a;179 来实现的。BGP 需要手工的方式去配置邻居。不需要直连&#xff0c;只要路由能通就可以建立邻居 IBGP 与 EBGP IBGP :(Internal BGP) :位于相同自治系统的 BGP 路由器之间的 BGP 邻接关…

esp32cam远程图传:AI Thinker ESP32-CAM -》 服务器公网 | 服务器 -》 电脑显示

用AI Thinker ESP32-CAM板子访问公网ip的5112端口并上传你的摄像头拍摄的图像视频数据&#xff0c;并写一段python程序打开弹窗接受图像实现超远程图像传输教程免费 1. 首先你要有一个公网ip也就是去买一台拥有公网的服务器电脑&#xff0c;我买的是腾讯云1年38元的服务器还可…

AIDD-人工智能药物-pyecharts-gallery

给大家安利一个NSC期刊级别的图-pyecharts-gallery 网址 https://gallery.pyecharts.org pyecharts-gallery 英文文档在这 - English Introduction is Here 项目简介 项目基于 pyecharts 2.0.3 版本进行展示Apache ECharts (incubating) 官方实例 项目须知 项目代码结构…