🚀 AI 一键生成 ptrade 策略代码

PTrade 趋势策略:三均线系统 (Triple MA) 交易法则

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

问题描述

怎么写三均线交易策略?

解决方案

三均线交易策略 (Three Moving Averages Strategy)

三均线策略是一种经典的趋势跟踪策略。它利用三条不同周期的移动平均线(例如短期、中期、长期)的排列关系来判断市场趋势。

策略逻辑

  1. 均线设置

    • 短期均线 (Short MA):反应价格的短期波动(如 5日线)。
    • 中期均线 (Medium MA):反应价格的中期趋势(如 10日线)。
    • 长期均线 (Long MA):反应价格的长期方向(如 20日线或60日线)。
  2. 交易信号

    • 买入信号(多头排列):当 短期均线 > 中期均线 > 长期均线 时,视为上涨趋势确立,全仓买入。
    • 卖出信号(空头排列或趋势破坏):当 短期均线 < 中期均线 (或者三者呈现空头排列 短<中<长)时,视为趋势结束或回调,清仓卖出。
    • 注:本示例代码采用“短期 < 中期”作为止盈/止损信号,反应更灵敏,避免利润回撤过多。

PTrade 策略代码实现

以下是完整的策略代码,您可以直接复制到 PTrade 回测环境中运行。

def initialize(context):
    """
    初始化函数,设置股票池和全局变量
    """
    # 1. 设置要操作的股票,这里以 恒生电子(600570.SS) 为例
    g.security = '600570.SS'
    set_universe(g.security)
    
    # 2. 设置均线周期参数
    g.short_period = 5   # 短期均线周期
    g.mid_period = 10    # 中期均线周期
    g.long_period = 20   # 长期均线周期
    
    # 3. 设置滑点和手续费(可选,回测常用设置)
    set_slippage(slippage=0.002) # 设置滑点
    set_commission(commission_ratio=0.0003, min_commission=5.0) # 设置手续费

def handle_data(context, data):
    """
    盘中运行函数,每个单位时间(如每天)运行一次
    """
    security = g.security
    
    # 1. 获取历史收盘价数据
    # 获取的数量需要足够计算最长周期的均线,这里多取2天以防万一
    count = g.long_period + 2
    # get_history 返回的是 DataFrame
    history = get_history(count, frequency='1d', field='close', security_list=security, fq='pre')
    
    # 检查数据是否获取成功
    if history is None or len(history) < g.long_period:
        log.info("历史数据不足,跳过本次计算")
        return
    
    # 提取收盘价序列 (Series)
    close_prices = history['close']
    
    # 2. 计算三条均线的值
    # 计算短期均线 (MA5)
    ma_short = close_prices[-g.short_period:].mean()
    # 计算中期均线 (MA10)
    ma_mid = close_prices[-g.mid_period:].mean()
    # 计算长期均线 (MA20)
    ma_long = close_prices[-g.long_period:].mean()
    
    # 获取当前持仓数量
    position = get_position(security).amount
    # 获取当前可用现金
    cash = context.portfolio.cash
    
    # 3. 生成交易信号并执行
    
    # 买入逻辑:多头排列 (短 > 中 > 长) 且 当前无持仓
    if ma_short > ma_mid and ma_mid > ma_long:
        if position == 0:
            # 全仓买入
            order_value(security, cash)
            log.info("买入信号触发:多头排列 (MA%s=%.2f > MA%s=%.2f > MA%s=%.2f)" % (
                g.short_period, ma_short, 
                g.mid_period, ma_mid, 
                g.long_period, ma_long
            ))
            
    # 卖出逻辑:短期均线下穿中期均线 (趋势转弱) 且 当前有持仓
    # 也可以修改为 ma_short < ma_mid < ma_long (完全空头排列才卖)
    elif ma_short < ma_mid:
        if position > 0:
            # 清仓卖出
            order_target(security, 0)
            log.info("卖出信号触发:趋势转弱 (MA%s=%.2f < MA%s=%.2f)" % (
                g.short_period, ma_short, 
                g.mid_period, ma_mid
            ))


代码详细解析

1. 初始化 (initialize)

  • set_universe: 设定策略操作的股票池。
  • 全局变量 (g.xxx): 我们将均线的周期(5, 10, 20)定义为全局变量。这样做的好处是,如果您想调整为(10, 30, 60),只需在 initialize 中修改数字即可,无需改动核心逻辑。

2. 数据获取 (get_history)

  • 我们使用 get_history 获取过去 g.long_period + 2 天的收盘价。
  • 注意:必须获取足够长度的数据才能计算出长期均线。例如计算20日均线,至少需要过去20天的数据。
  • fq='pre':使用前复权数据,这在股票回测中非常重要,可以避免分红配股导致的价格跳空影响均线计算。

3. 均线计算

  • 利用 Pandas Series 的切片和 mean() 方法计算均值。
  • close_prices[-5:] 表示取最后5个数据。

4. 交易逻辑

  • 买入:严格遵守 MA_Short > MA_Mid > MA_Long。这代表短期爆发力强,且中长期趋势向上,是最稳健的进场点。
  • 卖出:代码中使用了 MA_Short < MA_Mid 作为卖出点。
    • 解释:虽然三均线策略对应的卖点通常是空头排列(短<中<长),但在实际A股交易中,等到三线完全空头排列时,股价往往已经跌去很多。因此,使用短期均线下穿中期均线作为止损/止盈信号,通常能更好地保住利润。

常见问题 Q&A

Q1: 如何修改均线的周期?

A:initialize 函数中,修改 g.short_periodg.mid_periodg.long_period 的值即可。例如改为 10, 30, 60:

g.short_period = 10
g.mid_period = 30
g.long_period = 60

Q2: 这个策略适合什么级别的K线?

A: 默认代码中的 get_history(..., frequency='1d') 是基于日线级别的。
如果您想做分钟级别的三均线策略(例如60分钟线),需要:

  1. 将策略运行频率设置为“分钟”。
  2. 将代码中的 frequency='1d' 改为 frequency='60m'

Q3: 为什么有时候会出现“未来函数”的警告?

A: 在 PTrade 回测中,如果在 handle_data 中直接获取当天的 close 价格并立即成交,可能包含了一点点未来信息(因为实际交易时你无法确切知道收盘价)。

  • 解决方法:PTrade 的 handle_data 在日线回测时通常是在收盘后或收盘前一刻运行。为了更严谨,可以使用 history[:-1] 来计算截止到昨天的均线,或者使用分钟回测在盘中实时计算。但在简单的日线趋势策略教学中,上述代码是标准的写法。

Q4: 如何同时操作多只股票?

A: 您需要将 g.security 设置为一个列表,并在 handle_data 中使用 for 循环遍历。
修改示例:

def initialize(context):
    g.security = ['600570.SS', '000001.SZ'] # 列表
    set_universe(g.security)
    # ... 其他参数 ...

def handle_data(context, data):
    for stock in g.security:
        # 后续逻辑中的 g.security 全部替换为 stock
        # get_history 需要单独对 stock 获取,或者批量获取后处理
        # ...