🚀 AI 一键生成 ptrade 策略代码

PTrade 交易风控:百分比移动止损 (Trailing Stop) 实现

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

问题描述

如何设置百分比移动止损?

解决方案

在PTrade中实现百分比移动止损(Trailing Stop),核心逻辑是记录持仓以来的最高价格,当当前价格从最高点回撤达到设定的百分比(例如回撤5%或10%)时,触发卖出信号。

这种策略可以让利润奔跑(价格上涨时止损线跟随上移),同时控制回撤风险。

策略逻辑步骤

  1. 初始化:在 initialize 中定义止损百分比(如 5%)和一个全局字典 g.high_prices 用来存储每只持仓股票的历史最高价。
  2. 更新最高价:在 handle_data 中,遍历当前持仓。如果当前价格高于记录的最高价,则更新最高价。
  3. 检查止损:计算 止损价 = 最高价 * (1 - 止损百分比)。如果 当前价格 <= 止损价,则执行清仓操作。
  4. 清理数据:卖出后,从字典中删除该股票的记录。

PTrade 策略代码示例

以下是一个完整的策略示例。为了演示效果,策略包含了一个简单的买入逻辑(示例中为买入平安银行),重点在于移动止损的实现。

def initialize(context):
    """
    初始化函数
    """
    # 1. 设置要操作的股票(示例:平安银行)
    g.security = '000001.SZ'
    set_universe([g.security])
    
    # 2. 设置移动止损参数
    # 止损百分比,例如 0.05 代表从最高点回撤 5% 止损
    g.stop_loss_pct = 0.05 
    
    # 3. 用于记录持仓股票的最高价
    # 格式: {'股票代码': 最高价格}
    g.high_prices = {} 
    
    # 4. 设置买入标志(仅用于演示买入)
    g.bought = False

def handle_data(context, data):
    """
    盘中运行函数
    """
    # ----------------------
    # 1. 简单的买入逻辑 (仅作演示,用于建立底仓)
    # ----------------------
    if not g.bought:
        # 全仓买入
        order_value(g.security, context.portfolio.cash)
        log.info("【买入】建立底仓: %s" % g.security)
        g.bought = True
        # 买入时,初始化最高价为当前价格
        g.high_prices[g.security] = data[g.security]['close']
    
    # ----------------------
    # 2. 百分比移动止损逻辑 (核心部分)
    # ----------------------
    
    # 获取当前所有持仓的股票代码
    positions = context.portfolio.positions.keys()
    
    # 遍历每一只持仓股票
    for stock in positions:
        # 获取该股票的持仓对象
        position = context.portfolio.positions[stock]
        
        # 如果持仓量为0,跳过(可能是刚卖出但列表未刷新的情况)
        if position.amount == 0:
            continue
            
        # 获取当前价格
        current_price = data[stock]['close']
        
        # --- A. 维护最高价逻辑 ---
        # 如果该股票不在记录中(可能是非策略买入或初始化遗漏),则以当前价作为初始最高价
        if stock not in g.high_prices:
            g.high_prices[stock] = current_price
            
        # 如果当前价格创出新高,更新最高价
        if current_price > g.high_prices[stock]:
            g.high_prices[stock] = current_price
            # log.info("【新高】%s 价格创新高: %.2f,止损线提升" % (stock, current_price))
        
        # --- B. 计算止损并执行 ---
        # 获取记录的历史最高价
        max_price = g.high_prices[stock]
        
        # 计算触发止损的价格阈值
        stop_price = max_price * (1 - g.stop_loss_pct)
        
        # 检查是否触发止损
        if current_price <= stop_price:
            log.info("【止损触发】%s 当前价: %.2f, 历史最高: %.2f, 触发价: %.2f (回撤 %.1f%%)" % 
                     (stock, current_price, max_price, stop_price, g.stop_loss_pct * 100))
            
            # 卖出该股票所有持仓
            order_target(stock, 0)
            
            # --- C. 清理数据 ---
            # 卖出后,删除该股票的最高价记录,防止影响下次交易
            if stock in g.high_prices:
                del g.high_prices[stock]
            
            # 重置演示用的买入标志(实际策略中不需要这行)
            if stock == g.security:
                g.bought = False

代码详解

  1. g.high_prices 字典

    • 这是实现移动止损的关键。我们不能只看成本价,必须记录持仓期间出现的最高价格
    • 使用字典结构 {'600570.SS': 80.5, '000001.SZ': 15.2} 可以同时管理多只股票。
  2. 更新机制

    • 在每个 handle_data 周期(分钟或日线),我们检查 current_price > g.high_prices[stock]。如果是,说明价格上涨了,我们将止损线向上拖动(更新最高价)。
  3. 触发机制

    • 止损线是动态计算的:stop_price = max_price * (1 - g.stop_loss_pct)
    • 一旦 current_price 跌破这个动态止损线,立即执行 order_target(stock, 0) 清仓。
  4. 数据清理

    • 非常重要的一步是 del g.high_prices[stock]。如果不删除,下次买入该股票时,可能会错误地使用很久以前的最高价来计算止损,导致刚买入就立刻卖出。

注意事项

  • 回测频率:如果是日线回测,止损判断是在收盘时进行的(或者基于收盘价)。如果是分钟回测,则是在每分钟结束时判断,分钟级能更灵敏地捕捉盘中跳水。
  • Python版本兼容性:代码使用了 % 格式化字符串(如 "%s" % var),这是为了兼容 Python 3.5 及更早版本,确保在所有 PTrade 环境中均可运行。
  • 持久化:如果是实盘交易,建议使用 pickle 模块在 after_trading_end 中保存 g.high_prices,并在 initialize 中读取。防止服务器重启导致最高价记录丢失(回测中不需要此步骤)。

Q&A

Q: 如何将移动止损改为固定成本止损?
A: 不需要维护 g.high_prices。直接使用 context.portfolio.positions[stock].cost_basis 获取持仓成本,然后判断 current_price <= cost_basis * (1 - 止损比例) 即可。

Q: 可以在盘中实时(Tick级别)止损吗?
A: 可以。将上述逻辑放入 tick_data(context, data) 函数中,并使用 order_tick 接口下单。但要注意 Tick 数据量大,逻辑需尽量精简。

Q: 为什么卖出后要删除 g.high_prices 中的记录?
A: 为了重置状态。如果不删除,当你再次买入同一只股票时,程序会误用上一次持仓时的最高价来计算止损,这通常会导致错误的立即止损。