🚀 AI 一键生成 ptrade 策略代码

PTrade 平台如何复现经典的海龟交易策略?(附源码)

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

问题描述

请帮我编写一个经典的海龟交易策略。

解决方案

这是一个基于PTrade量化交易平台的**经典海龟交易策略(Turtle Trading Strategy)**实现。

策略核心逻辑

海龟交易法则是一个著名的趋势跟随策略,主要包含以下几个核心要素:

  1. 入场(唐奇安通道突破)
    • 当价格突破过去20个交易日的最高价时,买入(做多)。
  2. 离场(止盈)
    • 当价格跌破过去10个交易日的最低价时,卖出平仓。
  3. 资金管理(ATR波动率)
    • 使用ATR(平均真实波幅)来计算仓位大小(Unit)。
    • 波动大时仓位小,波动小时仓位大,旨在让每笔交易的风险恒定(通常为总资金的1%)。
  4. 加仓(金字塔式)
    • 如果价格在买入后继续上涨 0.5倍ATR,则加仓1个Unit,通常最多加仓4次。
  5. 止损
    • 当价格比最后一次买入价下跌 2倍ATR 时,全仓止损。

PTrade 策略代码

import numpy as np
import pandas as pd

def initialize(context):
    """
    策略初始化函数
    """
    # 1. 设置股票池 (这里以沪深300ETF为例,也可以替换为具体股票列表)
    g.security_list = ['510300.SS']
    set_universe(g.security_list)
    
    # 2. 策略参数设置
    g.N_window = 20        # ATR计算周期
    g.entry_window = 20    # 入场周期 (突破20日高点)
    g.exit_window = 10     # 离场周期 (跌破10日低点)
    g.risk_ratio = 0.01    # 每次交易风险占总资金的比例 (1%)
    g.max_units = 4        # 最大允许持仓单元数
    
    # 3. 全局变量,用于记录交易状态
    # 记录每只股票上一次的买入价格(用于加仓和止损判断)
    g.last_entry_prices = {} 
    # 记录每只股票当前的持仓单元数量
    g.hold_units = {}
    
    # 初始化状态字典
    for stock in g.security_list:
        g.last_entry_prices[stock] = 0.0
        g.hold_units[stock] = 0

def before_trading_start(context, data):
    """
    盘前处理:可以在这里预计算一些指标,或者处理非交易逻辑
    """
    pass

def get_atr(stock, window):
    """
    计算ATR (平均真实波幅)
    """
    # 获取历史数据,多取1天用于计算前一日收盘价
    h = get_history(window + 1, '1d', ['high', 'low', 'close'], stock, fq='pre', include=False)
    
    if len(h) < window + 1:
        return None
        
    high = h['high'].values
    low = h['low'].values
    close = h['close'].values
    
    tr_list = []
    # 从第二天开始计算TR
    for i in range(1, len(close)):
        hl = high[i] - low[i]
        hc = abs(high[i] - close[i-1])
        lc = abs(low[i] - close[i-1])
        tr = max(hl, hc, lc)
        tr_list.append(tr)
    
    # 计算ATR (简单平均)
    atr = np.mean(tr_list)
    return atr

def handle_data(context, data):
    """
    盘中每分钟/每日运行的逻辑
    """
    # 获取当前账户总资产
    total_value = context.portfolio.portfolio_value
    cash = context.portfolio.cash
    
    for stock in g.security_list:
        # 1. 数据准备
        # 获取过去 N 天的历史数据用于计算唐奇安通道
        # 需要多取数据以确保计算准确,这里取 max(entry_window, exit_window) + 缓冲
        hist_len = max(g.entry_window, g.exit_window) + 5
        h = get_history(hist_len, '1d', ['high', 'low', 'close'], stock, fq='pre', include=False)
        
        if len(h) < g.entry_window:
            log.info("历史数据不足,跳过 %s" % stock)
            continue
            
        # 计算唐奇安通道上轨 (过去20天的最高价)
        donchian_high = h['high'][-g.entry_window:].max()
        # 计算唐奇安通道下轨 (过去10天的最低价)
        donchian_low = h['low'][-g.exit_window:].min()
        
        # 计算ATR
        atr = get_atr(stock, g.N_window)
        if atr is None or atr == 0:
            continue
            
        # 获取当前价格
        current_price = data[stock]['close']
        
        # 获取当前持仓
        position = get_position(stock)
        current_amount = position.amount
        
        # ---------------------------------------------------
        # 策略逻辑 A: 无持仓,检查是否满足入场条件
        # ---------------------------------------------------
        if current_amount == 0:
            # 突破20日高点
            if current_price > donchian_high:
                # 计算 1个 Unit 的数量
                # Unit = (总资金 * 1%) / ATR
                # 含义:如果价格波动 1N (1个ATR),账户损失 1%
                unit_value = total_value * g.risk_ratio
                shares_per_unit = int(unit_value / atr / 100) * 100 # 向下取整到100股
                
                if shares_per_unit >= 100 and cash >= shares_per_unit * current_price:
                    order(stock, shares_per_unit)
                    g.last_entry_prices[stock] = current_price
                    g.hold_units[stock] = 1
                    log.info("【开仓】%s 突破20日高点(%.2f),买入1单元(%d股),ATR=%.3f" % (
                        stock, donchian_high, shares_per_unit, atr))
        
        # ---------------------------------------------------
        # 策略逻辑 B: 有持仓,检查加仓、止损、止盈
        # ---------------------------------------------------
        else:
            last_entry = g.last_entry_prices[stock]
            units = g.hold_units[stock]
            
            # 1. 止损检查:价格比最后买入价下跌 2N
            stop_loss_price = last_entry - 2 * atr
            if current_price < stop_loss_price:
                order_target(stock, 0)
                g.hold_units[stock] = 0
                g.last_entry_prices[stock] = 0
                log.info("【止损】%s 触发止损(现价%.2f < 止损价%.2f),清仓" % (
                    stock, current_price, stop_loss_price))
                continue # 止损后跳过后续逻辑
            
            # 2. 止盈离场:跌破10日低点
            if current_price < donchian_low:
                order_target(stock, 0)
                g.hold_units[stock] = 0
                g.last_entry_prices[stock] = 0
                log.info("【止盈】%s 跌破10日低点(%.2f),清仓离场" % (
                    stock, donchian_low))
                continue
            
            # 3. 加仓逻辑:价格比最后买入价上涨 0.5N
            # 且持仓未达到最大限制
            add_entry_price = last_entry + 0.5 * atr
            if current_price > add_entry_price and units < g.max_units:
                # 计算加仓数量 (保持Unit定义一致)
                unit_value = total_value * g.risk_ratio
                shares_per_unit = int(unit_value / atr / 100) * 100
                
                if shares_per_unit >= 100 and cash >= shares_per_unit * current_price:
                    order(stock, shares_per_unit)
                    g.last_entry_prices[stock] = current_price # 更新最后买入价
                    g.hold_units[stock] += 1
                    log.info("【加仓】%s 上涨0.5N(现价%.2f > 判定价%.2f),加仓第%d单元" % (
                        stock, current_price, add_entry_price, g.hold_units[stock]))

代码关键点解析

  1. ATR计算 (get_atr)

    • ATR是海龟策略的灵魂。它衡量了市场的波动性。
    • 代码中手动计算了TR(真实波幅),然后取平均值得到ATR。
    • get_history 获取的数据包含了最高价、最低价和收盘价,这是计算ATR必须的。
  2. 头寸规模 (Unit Sizing)

    • shares_per_unit = int(unit_value / atr / 100) * 100
    • 这是海龟法则的核心风控逻辑。当ATR(波动)大时,计算出的股数会变少;波动小时,股数变多。这保证了无论市场波动如何,每一笔交易承担的绝对风险金额(总资产的1%)是基本恒定的。
  3. 唐奇安通道 (Donchian Channel)

    • donchian_high:过去20天的最高价。
    • donchian_low:过去10天的最低价。
    • 注意:计算通道时使用了 include=False 或切片 [:-1] 的逻辑(代码中直接取历史数据,不包含当前时刻),这是为了避免“用到未来数据”或“当前价格瞬间突破即成交”的回测陷阱,通常突破是指突破过去N天的极值。
  4. 加仓与止损

    • 加仓依据:current_price > last_entry + 0.5 * atr
    • 止损依据:current_price < last_entry - 2 * atr
    • 这里使用了 g.last_entry_prices 字典来专门记录上一次动作的价格,这是实现金字塔加仓的关键。

常见问题 Q&A

Q: 为什么代码中要用 int(... / 100) * 100?
A: A股市场买入必须是100股的整数倍(1手)。如果不取整,下单接口可能会报错或被拒单。

Q: 这个策略适合所有股票吗?
A: 海龟策略是典型的趋势跟踪策略。它在有明显长期趋势的行情中表现最好(如大牛市或大熊市)。在震荡市(价格上下波动但无方向)中,该策略会频繁触发止损,导致连续小额亏损(俗称“来回打脸”)。因此,选股(选择波动性大、趋势性强的标的)非常重要。

Q: 如何在回测中查看效果?
A: 将此代码复制到PTrade的研究或回测界面,设置好回测时间段(建议包含牛熊周期,如2018-2022),设置初始资金,点击运行即可。

Q: g.security_list 可以放多只股票吗?
A: 可以。代码已经使用了 for stock in g.security_list: 循环结构,支持多只股票同时运行。但要注意资金分配,如果股票太多,可能导致资金不足以开新仓。