3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在 JoinQuant 平台中,关于 avg_cost 计算浮动盈亏以及拆分合并的处理,主要与是否开启动态复权(真实价格)模式以及**交易标的的类型(如场内基金)**有关。
根据 JoinQuant API 文档,如果您在 initialize 函数中开启了动态复权(真实价格)模式:
set_option('use_real_price', True)
每到新的一天,如果持仓中的股票发生了拆合或者分红等影响复权因子的情形,系统会根据复权因子自动调整股票的数量。为了保证 context.portfolio.total_value(总资产)不变,持仓数量会相应增加或减少,同时 avg_cost 也会被系统自动按比例调整,因此理论上不会出现因为拆分导致直接浮亏 50% 的情况。
您提到的 512690.XSHG 属于场内基金(ETF)。在 JoinQuant 的官方文档中有特别的注意事项:
注意: 对期货不生效,对场内基金会生效,但因场内基金在拆分/合并时除权日披露不标准,目前采用的是折算基准日,和实际除权日可能有差异,鉴于此原因不建议给含有场内基金的策略开启动态复权。
正是因为场内基金的除权日和折算基准日存在时间差,导致系统在某一天更新价格时,持仓数量和 avg_cost 可能没有在同一天同步调整,从而在回测或模拟中表现为巨大的“浮亏”或“浮盈”。
针对这种情况,建议采用以下几种方式来处理策略中的持仓盈亏计算:
不要依赖 context.portfolio.positions[security].avg_cost 来计算盈亏。您可以在买入时,记录当时的前复权价格,并在后续判断时,获取当前的前复权价格进行对比。
def initialize(context):
set_option('use_real_price', True)
g.buy_prices = {} # 记录买入时的前复权价格
def market_open(context):
security = '512690.XSHG'
# 获取当前的前复权价格
current_price = get_price(security, count=1, end_date=context.current_dt, frequency='1m', fields=['close'], fq='pre')['close'][0]
# 买入逻辑
if condition_to_buy:
order(security, 1000)
g.buy_prices[security] = current_price
# 计算浮动盈亏比例
if security in context.portfolio.positions and security in g.buy_prices:
cost_price = g.buy_prices[security]
profit_ratio = (current_price - cost_price) / cost_price
log.info(f"{security} 当前浮动盈亏比例: {profit_ratio*100:.2f}%")
注:get_price 或 attribute_history 默认返回的都是基于当天的前复权价格,这样计算出的盈亏比例是准确的,不受拆分合并的干扰。
如果您主要交易的是场内基金,且依赖系统的 avg_cost,由于平台数据的局限性,您可以提前查阅该 ETF 的拆分/折算公告,在策略中硬编码避开这些日期进行交易和盈亏判断。
如果您只做回测,可以关闭动态复权模式(即不调用 set_option('use_real_price', True))。此时回测全程使用基于回测当天的前复权价格,价格是连续的,avg_cost 也是连续的,不会出现突变。但强烈不建议在模拟交易中使用此方法,因为这会导致下单价格与真实市场价格不符。