🚀 AI 一键生成 ptrade 策略代码

PTrade 策略风控教程:如何用代码实现追踪止损(Trailing Stop-Loss)?

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

问题描述

请帮我编写一个追踪止损(Trailing Stop-Loss)的函数

解决方案

这是一个为您编写的适用于 PTrade 平台的 追踪止损(Trailing Stop-Loss) 函数。

策略逻辑说明

追踪止损的核心逻辑是:记录持仓以来的最高价格(High Watermark),当当前价格从最高点回撤达到设定的百分比时,触发卖出。

  1. 初始化:在 initialize 中定义一个全局字典 g.high_prices 用来存储每只股票的最高价,以及设定回撤阈值 g.trailing_gap
  2. 更新最高价:在每个交易周期(handle_data),检查持仓股票的当前价格。如果当前价格高于记录的最高价,则更新最高价。
  3. 触发止损:计算 止损价 = 最高价 * (1 - 回撤阈值)。如果 当前价格 <= 止损价,则清仓卖出。
  4. 清理数据:卖出后,从字典中移除该股票的记录,以便下次买入时重新计算。

PTrade 策略代码

def initialize(context):
    """
    初始化函数
    """
    # 设置股票池(示例:恒生电子)
    g.security = '600570.SS'
    set_universe(g.security)
    
    # 设定追踪止损的回撤阈值 (例如 5%)
    g.trailing_gap = 0.05
    
    # 用于存储每只持仓股票的历史最高价(High Watermark)
    # 格式: {'股票代码': 最高价格}
    g.high_prices = {}
    
    # 简单的买入标记,用于演示
    g.bought = False

def handle_data(context, data):
    """
    盘中运行函数
    """
    # ---------------------------------------------------
    # 1. 简单的买入逻辑(仅用于演示,以便有持仓可以测试止损)
    # ---------------------------------------------------
    if not g.bought:
        # 全仓买入示例股票
        order_target_value(g.security, context.portfolio.cash)
        g.bought = True
        log.info("演示买入: %s" % g.security)

    # ---------------------------------------------------
    # 2. 调用追踪止损函数
    # ---------------------------------------------------
    check_trailing_stop(context, data)


def check_trailing_stop(context, data):
    """
    追踪止损核心函数
    """
    # 获取当前账户所有持仓的股票代码列表
    # context.portfolio.positions 包含所有持仓信息
    holding_list = list(context.portfolio.positions.keys())
    
    # 遍历每一只持仓股票
    for stock in holding_list:
        position = context.portfolio.positions[stock]
        
        # 如果持仓数量为0,跳过(可能是已卖出但对象还在缓存中)
        if position.amount == 0:
            # 如果该股票还在最高价记录中,清理掉
            if stock in g.high_prices:
                del g.high_prices[stock]
            continue
            
        # 获取当前价格
        # 注意:data[stock] 获取的是 SecurityUnitData 对象
        current_price = data[stock]['close']
        
        # ---------------------------------------------------
        # 逻辑 A: 初始化或更新最高价 (High Watermark)
        # ---------------------------------------------------
        # 如果该股票不在记录中(刚买入),或者当前价格创新高
        if stock not in g.high_prices:
            # 刚买入时,将最高价初始化为当前价(或者可以使用持仓成本 position.cost_basis)
            g.high_prices[stock] = current_price
            log.info("初始化追踪止损记录: %s, 当前价: %.2f" % (stock, current_price))
        elif current_price > g.high_prices[stock]:
            # 创新高,更新最高价
            old_high = g.high_prices[stock]
            g.high_prices[stock] = current_price
            log.info("更新最高价: %s, 从 %.2f -> %.2f" % (stock, old_high, current_price))
            
        # ---------------------------------------------------
        # 逻辑 B: 计算止损线并检查是否触发
        # ---------------------------------------------------
        # 计算触发止损的价格
        high_price = g.high_prices[stock]
        stop_price = high_price * (1 - g.trailing_gap)
        
        # 检查是否跌破止损价
        if current_price <= stop_price:
            log.warning("触发追踪止损: %s" % stock)
            log.warning("历史最高价: %.2f, 设定回撤: %.1f%%, 止损触发价: %.2f, 当前价: %.2f" % (
                high_price, 
                g.trailing_gap * 100, 
                stop_price, 
                current_price
            ))
            
            # 执行卖出操作:清仓
            order_target(stock, 0)
            
            # 卖出后,从记录字典中移除该股票,防止重复逻辑或干扰下次交易
            del g.high_prices[stock]

代码关键点解析

  1. g.high_prices 字典

    • 这是实现追踪止损的关键。因为 handle_data 是循环运行的,我们需要一个持久的变量来记住“这只股票自从我买入以来,最高涨到了多少”。
    • 使用字典结构 {'600570.SS': 50.5, '000001.SZ': 12.3} 可以同时管理多只股票的止损逻辑。
  2. context.portfolio.positions

    • 我们遍历 context.portfolio.positions 而不是 g.security,这样可以确保函数对账户里所有实际持有的股票生效,无论它们是如何买入的。
  3. 初始化逻辑

    • if stock not in g.high_prices: 这一步处理刚买入的情况。通常我们将“当前价”设为初始最高价。如果您希望更保守,也可以使用 position.cost_basis(持仓成本)作为初始基准。
  4. Python 版本兼容性

    • 代码使用了 % 格式化字符串(例如 "当前价: %.2f" % current_price),这是为了确保在 PTrade 可能使用的旧版本 Python(如 Python 3.5)中也能完美运行,避免使用 f-string 导致语法错误。

如何在您的策略中使用

  1. check_trailing_stop 函数完整复制到您的策略代码底部。
  2. initialize 函数中添加 g.high_prices = {}g.trailing_gap = 0.05(您可以修改 0.05 为您想要的比例,如 0.10 代表 10%)。
  3. handle_data 函数的末尾调用 check_trailing_stop(context, data)

Q&A

Q1: 这个函数支持分钟级别回测吗?
A1: 支持。handle_data 在分钟回测模式下每分钟运行一次,该函数会实时更新分钟线收盘价作为最高价,并在盘中触发止损。

Q2: 如果我手动卖出了一部分股票,这个函数会出错吗?
A2: 不会。函数中使用 order_target(stock, 0) 是清仓指令。如果您手动卖出了部分股票,context.portfolio.positions 中的数量会更新,函数会继续对剩余持仓进行追踪止损。如果您手动全卖了,position.amount 变为 0,代码中的判断逻辑会清理掉对应的 g.high_prices 记录。

Q3: 如何修改为“固定价格止损”而不是“追踪止损”?
A3: 如果需要固定价格止损(例如亏损 5% 就卖,不管中间涨了多少),只需将 g.high_prices[stock] 的更新逻辑去掉,始终将其固定为 position.cost_basis(持仓成本价)即可。