🚀 AI 一键生成 joinquant 策略代码
立即体验

joinquant 真实价格回测:use_real_price 真实价格模式与红利税计算机制详解

joinquant | 发布时间: 2026/7/21
以下内容由 EasyQuant 生成。

问题描述

请根据以下 SEO 主题生成完整页面内容:

Title: joinquant 真实价格回测:use_real_price 与红利税计算机制

Question: 开启 use_real_price 真实价格模式后,聚宽回测是如何处理分红送股和扣税的?

解决方案

joinquant 真实价格回测:use_real_price 与红利税计算机制详解

在量化回测中,如何处理股票的分红、送股、配股及红利税是决定回测真实性的关键因素。聚宽(JoinQuant)提供了两种回测模式:传统前复权回测模式真实价格(动态复权)回测模式。本文将深度解析开启 set_option('use_real_price', True) 后的账户处理机制及红利税扣除细节。


一、 什么是真实价格(动态复权)模式?

initialize 初始化函数中,可以通过以下代码开启真实价格模式:

def initialize(context):
    # 开启真实价格模式(强烈推荐)
    set_option('use_real_price', True)

1. 真实价格模式与传统前复权模式的区别

  • 传统前复权模式(use_real_price=False
    不论回测的时间跨度如何,所有历史数据都是基于今天(或回测当天)的复权因子进行前复权处理的。这种模式下,历史交易使用的是非真实的“虚拟低价”,且由于引入了未来的复权因子,容易产生未来函数,导致回测结果失真。
  • 真实价格模式(use_real_price=True
    回测运行到历史某天时,交易系统使用当时的真实历史价格进行撮合成交。如果策略通过 historyattribute_history 获取历史价格,系统会实时使用当时的复权因子对历史价格进行前复权。这有效避免了未来函数,保证了交易撮合与持仓股数的真实性。

二、 真实价格模式下的分红送股处理

当持仓中的股票发生拆分、合并或分红时,真实价格模式会按照历史实际情况对账户进行动态调整:

  1. 股数与现金自动调整
    每到新的一天,如果持仓股发生送转股或分红,系统会自动在账户中增加相应的现金或调整持股数量,并在回测日志中进行提示。
  2. 向下取整原则
    如果因送配股调整后的持仓股数出现小数,系统会向下取整到整数股。为了保证账户总资产(context.portfolio.total_value)不因取整而减少,多余的碎股价值会略微补偿到可用资金(context.portfolio.available_cash)中。
  3. API 数据的一致性
    在不同日期调用 history 等 API 拿到的历史价格可能不同,因为它们是基于“当前逻辑日期”前复权的价格。因此,切勿跨日期缓存 API 返回的价格结果

三、 股息红利税的计算机制

在实际 A 股交易中,红利税是根据持股时间实行差别化税率的(持股超1年免税,1个月以内扣20%,1个月至1年扣10%),且在卖出时由券商扣收。

聚宽回测与模拟交易中的简化扣税规则

由于回测和模拟交易系统在分红当天需要将分红现金发放到账户,而系统无法预知用户未来何时会卖出该股票(即无法准确计算持仓时间),因此聚宽采取了以下统一的处理方式:

  • 统一扣税税率:在回测及模拟交易中,分红派息时统一按照 20% 的税率 预先计算并扣除红利税。
  • 到账金额计算
    $$\text{实际到账分红现金} = \text{每股税前分红} \times \text{持股数量} \times (1 - 20%)$$
    扣税后的净分红资金会在除权除息日当天直接发放至账户的可用资金中。

四、 典型策略编写模板

以下是一个开启了 use_real_price 的标准均线策略模板:

import jqdata

def initialize(context):
    # 1. 开启真实价格模式,规避未来函数,启用真实分红送股处理
    set_option('use_real_price', True)
    
    # 2. 设置基准
    set_benchmark('000300.XSHG')
    
    # 3. 设定操作股票
    g.security = '000001.XSHE'
    
    # 4. 每日运行
    run_daily(market_open, time='every_bar')

def market_open(context):
    security = g.security
    # 获取基于当天逻辑日前复权的 5 日收盘价
    close_data = attribute_history(security, 5, '1d', ['close'])
    MA5 = close_data['close'].mean()
    current_price = close_data['close'][-1]
    cash = context.portfolio.available_cash

    # 均线突破买入
    if current_price > 1.01 * MA5:
        order_value(security, cash)
        log.info("Buying %s" % (security))
    # 跌破均线卖出
    elif current_price < MA5 and context.portfolio.positions[security].closeable_amount > 0:
        order_target(security, 0)
        log.info("Selling %s" % (security))