🚀 AI 一键生成 joinquant 策略代码

JoinQuant 策略中如何响应股票分红送股事件?on_event 详解

joinquant | 发布时间: 2025/12/8
以下内容由 EasyQuant 生成。

问题描述

当持仓的股票分红时,我如何能收到通知并执行相应操作?

解决方案

在 JoinQuant 聚宽平台中,要实现持仓股票分红时收到通知并执行操作,主要通过 on_event(context, event) 回调函数来实现。

当账户中的持仓标的发生分红送股(DividendsEvent)或强行平仓(ForcedLiquidationEvent)时,系统会自动触发该函数。

实现步骤

  1. 定义 on_event 函数:在策略代码中添加此函数。
  2. 判断事件类型:检查 event 是否为分红事件。
  3. 获取分红信息:从 event 对象中提取股票代码、现金分红金额或送股比例。
  4. 执行操作:编写逻辑发送通知(如 send_message)或进行交易(如红利再投资)。

策略代码示例

以下是一个完整的策略示例。该策略会买入一只股票,并在该股票发生分红时打印日志、发送微信消息(仅模拟交易生效),并演示如何利用分红现金进行再投资。

# -*- coding: utf-8 -*-
from jqdata import *

def initialize(context):
    # 开启真实价格模式(强烈建议开启,否则分红处理可能不准确)
    set_option('use_real_price', True)
    # 设置基准
    set_benchmark('000300.XSHG')
    # 设置手续费
    set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
    
    # 定义一个全局变量,用于演示买入股票
    g.security = '000001.XSHE' 
    
    # 每天开盘运行,确保有持仓
    run_daily(market_open, time='09:30')

def market_open(context):
    # 如果没有持仓,则买入,以便测试分红事件
    if g.security not in context.portfolio.positions:
        order_value(g.security, 10000)
        log.info("买入股票: %s" % g.security)

# ----------------------------------------------------------------------
# 核心函数:事件回调
# ----------------------------------------------------------------------
def on_event(context, event):
    """
    当账户中持仓的标的发生特定事件时被调用
    """
    # 判断是否为分红送股事件
    # event.name 的值为 'Dividends' 代表分红
    if event.name == 'Dividends':
        # 获取标的代码
        security = event.security
        
        # 获取分红具体信息
        # event.dividends 是一个列表,通常包含一个字典
        # bonus_pre_tax: 税前现金分红
        # scale_factor: 送转股比例
        div_info = event.dividends[0]
        cash_div = div_info.get('bonus_pre_tax', 0)
        stock_div = div_info.get('scale_factor', 0)
        
        # 1. 构建通知消息
        msg = "【分红通知】股票 {} 发生分红!现金分红: {}, 送转股比例: {}".format(
            security, cash_div, stock_div
        )
        
        # 2. 打印日志
        log.info(msg)
        
        # 3. 发送微信消息 (仅在模拟交易中绑定微信后生效,回测中会被忽略)
        send_message(msg)
        
        # 4. 执行相应操作 (示例:红利再投资)
        # 注意:分红的现金通常在当天收盘后或第二天到账,具体取决于交易所规则和回测机制
        # 在回测中,现金通常在分红日直接可用
        if cash_div > 0:
            # 计算分红总金额 (每股分红 * 持仓数量)
            # 注意:这里只是估算,实际资金会自动加到 available_cash 中
            position = context.portfolio.positions[security]
            estimated_cash = cash_div * position.total_amount
            
            log.info("收到现金分红,尝试执行红利再投资操作...")
            
            # 尝试用可用资金买入更多该股票
            # 注意:需要判断当前可用资金是否足够买入一手
            current_price = position.price
            if context.portfolio.available_cash > current_price * 100:
                order_value(security, context.portfolio.available_cash)
                log.info("红利再投资下单完成")
            else:
                log.info("可用资金不足以买入一手,跳过再投资")

代码解析

  1. on_event(context, event): 这是聚宽提供的标准回调函数。你不需要在 run_daily 中调用它,系统会在事件发生时自动触发。
  2. event 对象:
    • event.name: 用于判断事件类型,分红事件为 'Dividends'
    • event.security: 发生分红的股票代码。
    • event.dividends: 包含分红详情的列表。
  3. send_message(msg): 这是一个非常实用的函数。在聚宽官网的模拟交易中,如果你绑定了微信,调用此函数会直接推送到你的手机微信上。在回测中调用此函数不会报错,但不会发送消息。
  4. set_option('use_real_price', True): 在处理分红和历史数据时,强烈建议开启真实价格模式(动态复权),这样账户的资金和持仓数量变化才符合真实市场的除权除息逻辑。

Q&A

Q: 回测和模拟交易中,分红到账的时间一致吗?
A: 在回测中,分红现金通常在除权除息日当天处理并反映在账户现金中。在模拟交易中,系统会根据交易所的实际公告和结算流程处理,通常也是在除权日进行除权处理,现金到账可能会遵循 T+N 的规则,具体视券商结算规则而定,但聚宽模拟盘通常简化处理,在除权日调整账户。

Q: 如果我不写 on_event 函数,分红还会自动到账吗?
A: 会的。on_event 只是一个通知机制,用于让你知道发生了分红并执行额外逻辑(如发消息、再投资)。即使不写这个函数,聚宽的交易引擎也会自动处理分红,你的持仓数量会根据送股比例增加,账户现金会根据分红金额增加(扣除税费后)。

Q: send_message 有发送限制吗?
A: 有限制。在模拟交易中,自定义消息(即通过 send_message 发送的)每个账号每天最多发送 5 条。如果超出限制,消息将发送失败。下单通知(系统自动发送的成交提醒)每天最多 60 条。

Q: 如何计算实际到手的现金分红?
A: event.dividends 中提供的是 bonus_pre_tax(税前分红)。在回测和模拟中,系统通常会按照默认税率(如 20% 或根据持仓时间计算的差异化税率,具体取决于平台当前的税费设置)自动扣除红利税。因此,账户实际增加的现金可能会少于 bonus_pre_tax * 持仓股数