🚀 AI 一键生成 ptrade 策略代码

PTrade 账户分析:计算特定持仓的持有期收益率

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

问题描述

如何计算单笔持仓的持有收益?

解决方案

在PTrade中,计算单笔标的(如股票)的持仓收益,主要通过获取持仓对象 Position 来实现。

你可以通过 get_position(security) 函数获取指定标的的持仓信息,然后利用其中的属性进行计算。

主要有两种方式:

  1. 直接获取系统计算好的浮动盈亏 (pnl)
  2. 手动计算:使用 (当前价 - 持仓成本) * 持仓数量

以下是具体的代码实现示例和说明。

策略代码示例

def initialize(context):
    # 初始化策略,设置股票池
    g.security = '600570.SS'
    set_universe(g.security)
    # 设置一个标志,用于控制只买入一次,方便观察后续收益变化
    g.bought = False

def handle_data(context, data):
    # 1. 模拟买入操作(仅为了产生持仓)
    if not g.bought:
        order(g.security, 1000)
        g.bought = True
        log.info("已买入 %s" % g.security)
        return # 买入当次循环暂不计算收益

    # 2. 获取持仓对象
    # get_position 返回的是一个 Position 对象
    position = get_position(g.security)

    # 3. 确保有持仓才进行计算
    if position.amount > 0:
        # --- 方法一:直接读取系统计算的浮动盈亏 ---
        # pnl: 浮动盈亏 (Profit and Loss)
        holding_pnl = position.pnl
        
        # --- 方法二:手动计算 (用于验证或自定义逻辑) ---
        # cost_basis: 持仓成本价 (通常包含手续费,取决于回测设置)
        cost_price = position.cost_basis
        # amount: 总持仓数量
        amount = position.amount
        # current_price: 当前市场价格
        current_price = data[g.security]['close']
        
        # 手动计算收益额
        manual_pnl = (current_price - cost_price) * amount
        
        # 计算收益率 (%)
        if cost_price > 0:
            return_rate = (current_price - cost_price) / cost_price * 100
        else:
            return_rate = 0.0

        # 4. 打印结果
        log.info("-" * 30)
        log.info("标的: %s" % g.security)
        log.info("当前价格: %.2f, 持仓成本: %.2f, 持仓数量: %d" % (current_price, cost_price, amount))
        log.info("【系统计算】浮动盈亏(pnl): %.2f" % holding_pnl)
        log.info("【手动计算】浮动盈亏: %.2f" % manual_pnl)
        log.info("【收益率】: %.2f%%" % return_rate)
        log.info("-" * 30)
    else:
        log.info("%s 当前无持仓" % g.security)

关键属性说明

Position 对象中(通过 get_position(security) 获取),以下属性是计算收益的关键:

属性名 类型 说明
pnl float 浮动盈亏。这是最直接的收益数据,代表当前持仓相对于成本的盈亏金额。
cost_basis float 持仓成本价。通常是加权平均成本。
amount int 总持仓数量
last_sale_price float 最新价格。持仓对象中记录的最新成交价,也可用于计算。

注意事项

  1. 期货交易:如果是期货策略,Position 对象区分多头和空头。
    • 多头浮动盈亏:position.long_pnl
    • 空头浮动盈亏:position.short_pnl
    • 多头持仓成本:position.long_cost_basis
    • 空头持仓成本:position.short_cost_basis
  2. 成本价 (cost_basis):在回测中,成本价的计算方式受 set_commission(佣金设置)的影响。如果设置了佣金,买入时的手续费通常会摊薄到 cost_basis 中,导致成本价略高于成交价。
  3. 数据更新频率:在 handle_data 中,data[security]['close'] 获取的是当前周期(如分钟或日线)的收盘价。在交易模式下,持仓信息的更新可能存在极短的延迟(通常在几秒内),但在回测中是即时的。

Q&A

Q: position.pnl 和我自己算的 (现价-成本)*数量 会有误差吗?
A: 通常情况下两者是一致的。微小的误差可能来源于浮点数精度问题,或者系统使用的“现价”来源(last_sale_price)与你在 data 中获取的价格有极细微的时间差(主要在实盘tick级别)。在回测中,它们通常完全相等。

Q: 如何计算账户的总收益,而不仅仅是单只股票?
A: 账户总收益可以通过 context.portfolio 对象获取。

  • context.portfolio.returns: 当前相对于初始资金的收益比例。
  • context.portfolio.pnl: 账户当前的浮动盈亏总额。
  • context.portfolio.portfolio_value: 当前账户总资产(现金+持仓市值)。

Q: 卖出股票后的收益去哪里看?
A: get_position 获取的是当前持仓的信息。一旦股票全部卖出,amount 变为 0,pnl 也会归零。卖出后的已实现收益会体现在账户的总资金 context.portfolio.cash 和总资产 context.portfolio.portfolio_value 的变化中。如果需要统计历史已平仓订单的收益,需要自行记录交易日志或分析 get_trades() 返回的成交记录。