🚀 AI 一键生成 ptrade 策略代码

如何在 PTrade 中实现一个基于 VWAP 的日内均值回归交易策略?

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

问题描述

请帮我写一个基于 VWAP 指标的日内交易策略。

解决方案

这是一个基于 VWAP (成交量加权平均价) 的日内趋势跟踪策略。

策略逻辑说明

  1. 核心指标 VWAP
    • 公式:VWAP = 当日累计成交额 / 当日累计成交量
    • 意义:VWAP 代表了当日市场参与者的平均持仓成本。
  2. 交易信号
    • 买入:当当前价格 上穿 VWAP 且超过一定阈值(例如 0.5%)时,认为多头力量强势,进行买入。
    • 卖出/止损:当当前价格 下穿 VWAP 且低于一定阈值时,或者在尾盘强制平仓时,卖出股票。
  3. 日内风控
    • 开盘避让:开盘前 15 分钟波动剧烈,VWAP 不稳定,不进行交易。
    • 尾盘清仓:每日 14:55 强制平仓,确保不持仓过夜(日内策略)。

PTrade 策略代码

import numpy as np
import pandas as pd

def initialize(context):
    """
    初始化函数,设置策略参数
    """
    # 设置要操作的股票,这里以 贵州茅台(600519.SS) 为例
    # 实际使用时可修改为其他流动性较好的标的
    g.security = '600519.SS'
    set_universe([g.security])
    
    # 策略参数设置
    g.threshold = 0.005  # 阈值 0.5%,用于过滤假突破
    g.is_intraday = True # 是否强制日内交易(收盘平仓)
    
    # 设置滑点和佣金(回测常用设置)
    set_commission(commission_ratio=0.0003, min_commission=5.0, type="STOCK")
    set_slippage(slippage=0.002)
    
    # 注册尾盘定时任务,用于日内平仓
    if g.is_intraday:
        run_daily(context, close_all_positions, time='14:55')

def before_trading_start(context, data):
    """
    盘前处理
    """
    log.info("盘前准备: %s" % context.blotter.current_dt)

def handle_data(context, data):
    """
    盘中每分钟运行一次
    """
    # 1. 时间控制
    current_dt = context.blotter.current_dt
    current_time = current_dt.strftime('%H:%M')
    
    # 避开开盘前15分钟,数据波动大且VWAP参考性弱
    if current_time < '09:45':
        return
    
    # 避开尾盘平仓时段,防止逻辑冲突
    if current_time >= '14:55':
        return

    security = g.security
    
    # 2. 获取当日分钟级历史数据来计算 VWAP
    # 获取当天开盘以来的分钟数据,最大取240根(4小时)
    # 注意:get_history 返回的是包含当前分钟的数据
    df = get_history(240, frequency='1m', field=['close', 'volume', 'money'], security_list=security, include=True)
    
    if df is None or len(df) == 0:
        return

    # 筛选出当日的数据(PTrade get_history 可能返回跨日数据,需按日期过滤)
    current_date_str = current_dt.strftime('%Y-%m-%d')
    # 将索引转为字符串日期进行匹配
    df['date_str'] = df.index.strftime('%Y-%m-%d')
    today_df = df[df['date_str'] == current_date_str]
    
    if len(today_df) == 0:
        return

    # 3. 计算 VWAP
    # VWAP = 累计成交额 / 累计成交量
    total_money = today_df['money'].sum()
    total_volume = today_df['volume'].sum()
    
    if total_volume == 0:
        return
        
    vwap = total_money / total_volume
    
    # 获取当前最新价格
    current_price = data[security]['price']
    
    # 4. 获取当前持仓
    position = get_position(security).amount
    available_cash = context.portfolio.cash
    
    # 5. 交易逻辑
    # 信号:价格 > VWAP * (1 + 阈值) -> 看多
    if current_price > vwap * (1 + g.threshold):
        if position == 0 and available_cash > 0:
            # 全仓买入
            order_value(security, available_cash)
            log.info("买入信号触发: 价格(%.2f) > VWAP(%.2f) * (1+%.3f)" % (current_price, vwap, g.threshold))
            
    # 信号:价格 < VWAP * (1 - 阈值) -> 看空/止损
    elif current_price < vwap * (1 - g.threshold):
        if position > 0:
            # 清仓卖出
            order_target(security, 0)
            log.info("卖出信号触发: 价格(%.2f) < VWAP(%.2f) * (1-%.3f)" % (current_price, vwap, g.threshold))

def close_all_positions(context):
    """
    收盘强制平仓函数
    """
    security = g.security
    position = get_position(security).amount
    
    if position > 0:
        log.info("尾盘强制平仓: %s" % security)
        order_target(security, 0)

代码关键点解析

  1. VWAP 计算方法

    • PTrade 没有直接提供当日实时 VWAP 的接口,因此我们使用 get_history 获取当日的分钟线数据。
    • money 字段代表成交额,volume 代表成交量。
    • 通过 today_df['money'].sum() / today_df['volume'].sum() 手动计算出截止当前分钟的 VWAP。
  2. 数据过滤

    • get_history(240, ...) 可能会获取到昨天尾盘的数据(如果是上午刚开盘)。
    • 代码中使用了 df[df['date_str'] == current_date_str] 确保只计算当日的成交量和成交额,保证 VWAP 的准确性。
  3. 阈值 (g.threshold)

    • 直接使用 Price > VWAP 容易在震荡市中产生大量无效交易(来回止损)。
    • 引入 0.005 (0.5%) 的缓冲带,只有价格显著偏离 VWAP 时才开仓,这有助于过滤噪音。
  4. 日内平仓

    • 使用 run_daily(..., time='14:55') 注册定时任务。
    • 这是日内策略(T+0 逻辑,但在 A 股 T+1 制度下,通常用于底仓做 T 或 ETF/可转债交易)的关键。
    • 注意:如果是 A 股普通股票(T+1),当日买入的股票当日无法卖出。此策略在 A 股市场更适合用于可转债ETF,或者你有底仓的情况下进行做 T 操作。如果是无底仓的纯 A 股买入,尾盘平仓会失败。

适用建议

  • 标的选择:建议选择波动率较大、流动性好的标的。
  • 市场限制
    • 股票 (T+1):此代码作为纯日内策略回测时,如果当日买入,尾盘是卖不掉的。若要用于股票,需修改为持有底仓的逻辑(即 order_target 调整仓位,而不是从 0 买入)。
    • 可转债/ETF (T+0):此代码完全适用,可以直接进行日内回转交易。

Q&A

Q: 如何在 A 股 T+1 制度下使用此策略?
A: 你需要有“底仓”。例如,你持有 1000 股茅台。

  • 当信号显示买入时,你买入 1000 股(此时持有 2000 股)。
  • 当信号显示卖出或尾盘时,你卖出 1000 股(此时持有 1000 股)。
  • 这样利用底仓实现了变相的 T+0。

Q: 为什么计算 VWAP 时要过滤日期?
A: get_history(count=N) 取的是最近 N 根 K 线。如果在早上 9:40 调用,取 240 根 K 线会包含昨天的大部分数据,导致 VWAP 计算错误。VWAP 定义是“当日”加权均价,所以必须剔除昨日数据。