Warning: file_exists(): open_basedir restriction in effect. File(/www/wwwroot/com.xiximiao.oa/com.cmstop/public/www/wp-content/db.php) is not within the allowed path(s): (/www/wwwroot/com.xiximiao.oa/com.cmstop/public/www/:/tmp/:/proc/:/var/log/nginx/:/www/wwwroot/com.xiximiao.oa/com.cmstop/public/:/www/wwwroot/com.xiximiao.oa/com.cmstop/vendor/:/www/wwwroot/com.xiximiao.oa/com.cmstop/ppk/) in /www/wwwroot/com.xiximiao.oa/com.cmstop/public/www/wp-includes/load.php on line 707
2387 每月轮动调仓的红利策略 三年期高股息率等权轮动策略 量化交易策略代码 » 轻知量化 QMT、PTrade、聚宽策略分享交流平台

2387 每月轮动调仓的红利策略 三年期高股息率等权轮动策略 量化交易策略代码

策略逻辑说明

本策略为高股息率动态轮动策略,核心逻辑如下:
  1. 选股机制
  • 基础筛选:全市场股票中选取市净率 > 0 且净资产收益率为正的标的
  • 股息率排序:计算近 3 年累计分红金额 / 当前总市值,筛选股息率前 10% 的股票
  • 流动性过滤:排除 ST/*ST / 退市 / 涨跌停 / 停牌个股
  • 定期优化:每月初从高股息池中精选前 30 只个股
  1. 组合构建
  • 等权重配置:将可用资金均分 30 份,每只股票初始占比 3.3%
  • 强制调仓:每月首个交易日卖出非名单内股票,买入新入选标的
  • 持仓控制:严格限制持仓数量为 30 只,避免过度分散
  1. 风险控制
  • 财务健康:要求连续 3 年实施现金分红
  • 估值保护:排除市净率为负的潜在问题企业
  • 极端行情规避:自动跳过涨跌停个股的交易
  • 分散投资:行业自然分散,避免单一行业过度集中
  1. 特殊处理
  • 分红数据校验:处理财务数据接口限制(单次最多 4000 行)
  • 时间窗口校准:准确计算三年期分红数据(365*3 天)
  • 动态调整:保留 10% 安全边际(取股息率 0-10% 区间)

策略代码

# 回测资金  10000000

from jqdata import *
import numpy as np
import pandas as pd
import warnings
warnings.filterwarnings("ignore")

#初始化函数 
def initialize(context):
    # 设定基准
    set_benchmark('510880.XSHG')
    set_option('use_real_price', True)
    set_option("avoid_future_data", True)
    log.set_level('system', 'error')
    g.stocknum = 30
    run_monthly(trade, 1, '10:00')
    
# 交易
def trade(context):
    end_date = context.previous_date 
    current_data = get_current_data()
    stocks = get_all_securities('stock', end_date).index.tolist()
    q = query(
        valuation.code
    ).filter(
        valuation.code.in_(stocks),
        valuation.pb_ratio > 0,
        indicator.inc_return>0
    )
    stocks = list(get_fundamentals(q).code)
    stocks = get_dividend_ratio_filter_list(context, stocks, False, 0, 0.1)[:100]
    
    stocks = [
        stock for stock in stocks if not (
                current_data[stock].paused or
                current_data[stock].is_st or
                ('ST' in current_data[stock].name) or
                ('*' in current_data[stock].name) or
                ('退' in current_data[stock].name) or
                (current_data[stock].last_price == current_data[stock].high_limit) or
                (current_data[stock].last_price == current_data[stock].low_limit)
        )]
    stocks = stocks[:g.stocknum]    
    
    for s in context.portfolio.positions:
        if s  not in stocks:
            order_target(s, 0)
            
    psize = context.portfolio.total_value/g.stocknum  
    for s in stocks:
        if len(context.portfolio.positions) >= g.stocknum:
                    break
        if s not in context.portfolio.positions:
            order_value(s, psize)
            
    record(stocknum=len(context.portfolio.positions))


#1-1 根据最近一年分红除以当前总市值计算股息率并筛选
get_dividend_ratio_filter_list 函数解锁后查看:

def get_dividend_ratio_filter_list(context, stock_list, sort, p1, p2):
    time1 = context.previous_date
    time0 = time1 - datetime.timedelta(days=365*3)
    #获取分红数据,由于finance.run_query最多返回4000行,以防未来数据超限,最好把stock_list拆分后查询再组合
    interval = 1000 #某只股票可能一年内多次分红,导致其所占行数大于1,所以interval不要取满4000
    list_len = len(stock_list)
    #截取不超过interval的列表并查询
    q = query(finance.STK_XR_XD.code, finance.STK_XR_XD.a_registration_date, finance.STK_XR_XD.bonus_amount_rmb
    ).filter(
        finance.STK_XR_XD.a_registration_date >= time0,
        finance.STK_XR_XD.a_registration_date <= time1,
        finance.STK_XR_XD.code.in_(stock_list[:min(list_len, interval)]))
    df = finance.run_query(q)
    #对interval的部分分别查询并拼接
    if list_len > interval:
        df_num = list_len // interval
        for i in range(df_num):
            q = query(finance.STK_XR_XD.code, finance.STK_XR_XD.a_registration_date, finance.STK_XR_XD.bonus_amount_rmb
            ).filter(
                finance.STK_XR_XD.a_registration_date >= time0,
                finance.STK_XR_XD.a_registration_date <= time1,
                finance.STK_XR_XD.code.in_(stock_list[interval*(i+1):min(list_len,interval*(i+2))]))
            temp_df = finance.run_query(q)
            df = df.append(temp_df)
    dividend = df.fillna(0)
    dividend = dividend.set_index('code')
    dividend = dividend.groupby('code').sum()
    temp_list = list(dividend.index) #query查询不到无分红信息的股票,所以temp_list长度会小于stock_list
    #获取市值相关数据
    q = query(valuation.code,valuation.market_cap).filter(valuation.code.in_(temp_list))
    cap = get_fundamentals(q, date=time1)
    cap = cap.set_index('code')
    #计算股息率
    DR = pd.concat([dividend, cap] ,axis=1, sort=False)
    DR['dividend_ratio'] = (DR['bonus_amount_rmb']/10000) / DR['market_cap']
    #排序并筛选
    DR = DR.sort_values(by=['dividend_ratio'], ascending=sort)
    final_list = list(DR.index)[int(p1*len(DR)):int(p2*len(DR))]
    return final_list
    
2025-02-24
⚠️
本站资源大多来自网络,仅供网友学习交流,未经作者或上传书面授权,请勿作他用。
站长 vx: xiangyin615 或者 留言反馈 ,我们将尽快处理。
Notice: When you of the legal rights be violate, please stir to vx: xiangyin615
个人中心
购物车
优惠劵
搜索