🚀 AI 一键生成 ptrade 策略代码

PTrade API 详解:get_history 函数 fill 参数的最佳实践

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

问题描述

获取历史行情时如何处理停牌或缺失的数据?

解决方案

在PTrade量化交易平台中,获取历史行情(如使用 get_historyget_price)时,针对停牌或数据缺失的情况,系统有一套默认的处理机制。

以下是关于PTrade如何处理停牌及缺失数据的详细说明和代码示例。

1. 停牌数据的默认处理机制

PTrade在获取历史数据时,不会跳过停牌日期。时间轴严格按照二级市场的交易日历排列。如果某只股票在某个交易日停牌,系统会使用停牌前一笔有效数据进行填充(Forward Fill)。

具体表现如下:

  • 价格字段(open, high, low, close, price): 使用停牌前最后一个交易日的收盘价进行填充。即:今日开盘价 = 今日收盘价 = 昨日收盘价
  • 成交量字段(volume): 填充为 0
  • 成交额字段(money): 填充为 0

策略启示:
在编写策略时,如果直接使用均线等指标,停牌期间的一字横盘数据会影响指标计算(例如导致波动率降低)。通常建议在开仓前过滤掉停牌的股票。

2. 分钟级缺失数据的处理(fill 参数)

在获取分钟级别数据时(特别是交易模式下),可能会遇到某一分钟没有成交导致的数据缺失。get_history 函数提供了一个 fill 参数来控制填充方式:

  • fill='pre':用上一分钟的数据填充当前时刻(前值填充)。
  • fill='nan'(默认):使用 NaN(Not a Number)进行填充。

3. 如何在代码中处理停牌

为了避免策略在停牌期间发出错误的交易信号,通常有以下两种处理方式:

方法一:使用 get_stock_status 主动过滤(推荐)

在交易逻辑执行前,先查询股票的 HALT 状态。

方法二:通过成交量判断

在获取历史数据后,判断 volume 是否为 0。

4. 代码示例

以下代码展示了如何在策略中识别并过滤停牌股票,以及获取历史数据后的验证逻辑。

def initialize(context):
    # 初始化股票池
    g.security = ['600570.SS', '000001.SZ', '600000.SS']
    set_universe(g.security)

def handle_data(context, data):
    # --- 方法一:使用 get_stock_status 过滤停牌股 (推荐) ---
    
    # 获取当前股票池中所有股票的停牌状态
    # 返回一个字典,Key为股票代码,Value为布尔值(True表示停牌,False表示未停牌)
    halt_status = get_stock_status(g.security, 'HALT')
    
    # 创建一个列表存储今日可交易的股票
    tradable_stocks = []
    
    for stock in g.security:
        if halt_status.get(stock, False):
            log.info("股票 %s 当前处于停牌状态,跳过处理。" % stock)
            continue
        else:
            tradable_stocks.append(stock)
            
    if len(tradable_stocks) == 0:
        return

    # --- 方法二:获取历史数据并观察停牌表现 ---
    
    # 获取过去5天的日线数据
    # 注意:PTrade不会跳过停牌日,停牌日会有数据,但Volume为0
    history_data = get_history(5, '1d', ['close', 'volume'], security_list=tradable_stocks)
    
    for stock in tradable_stocks:
        # 获取该股票的收盘价和成交量序列
        # 注意:get_history返回的数据结构在不同Python版本或参数下可能不同
        # 这里假设返回的是DataFrame或可以通过query查询
        
        # 针对多只股票返回的DataFrame进行查询
        stock_df = history_data.query('code == "%s"' % stock)
        
        if len(stock_df) > 0:
            # 获取最近一个交易日的数据
            last_close = stock_df['close'].iloc[-1]
            last_volume = stock_df['volume'].iloc[-1]
            
            # 再次确认:如果成交量为0,通常意味着停牌(或极端无流动性)
            if last_volume == 0:
                log.info("股票 %s 历史数据成交量为0,疑似停牌或无成交。" % stock)
            else:
                # 正常的交易逻辑
                # 例如:简单的均线策略
                avg_price = stock_df['close'].mean()
                current_price = data[stock]['close']
                
                if current_price > avg_price:
                    log.info("股票 %s 价格高于5日均线,且未停牌,执行买入检查..." % stock)
                    # order(stock, 100) # 示例下单

5. 总结

  1. 数据连续性:PTrade 历史数据在时间轴上是连续的,停牌日不会被剔除。
  2. 填充规则:停牌日价格沿用前值,成交量为 0。
  3. 最佳实践:不要依赖 get_history 返回的数据来被动发现停牌,而应在 handle_databefore_trading_start 中使用 get_stock_status(security_list, 'HALT') 主动过滤停牌股票,以提高策略效率和准确性。

Q&A

Q1: 如果我在回测中使用了 get_history 获取了包含停牌日的数据计算均线,会有什么影响?
A1: 停牌期间价格为一条直线(前值填充),这会导致移动平均线(MA)在停牌期间走平,且波动率指标(如ATR、StdDev)会迅速下降。如果策略依赖波动率突破,可能会在复牌瞬间产生错误的信号。建议在计算指标前剔除成交量为0的行,或者使用 get_stock_status 预先过滤。

Q2: get_priceget_history 在处理停牌数据上有什么区别吗?
A2: 两者在处理停牌数据的逻辑上是一致的。都会返回停牌日的记录,价格为前收盘价,成交量为0。区别主要在于参数和返回格式,get_price 支持指定具体的时间段(start_date, end_date),而 get_history 指定的是数量(count)。

Q3: 分钟线数据缺失时,fill='nan'fill='pre' 哪个更好?
A3: 这取决于策略类型。如果是基于价格连续性的趋势策略,使用 fill='pre'(前值填充)可以保持序列完整,避免计算报错。如果是对数据质量要求极高的统计套利策略,使用 fill='nan' 可以让你明确知道哪些时间点没有真实成交,从而避免基于虚假数据下单。注意 fill 参数主要在交易模式下生效。