🚀 AI 一键生成 ptrade 策略代码

PTrade 选股技巧:如何使用 `get_stock_info` 和上市日期 (listed_date) 过滤股票?

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

问题描述

在选股时,我如何过滤掉那些上市时间少于90天的股票?

解决方案

在PTrade中,过滤上市时间不足90天的股票主要依赖于 get_stock_info 接口来获取股票的上市日期(listed_date),然后结合 datetime 模块计算当前回测/交易日期与上市日期的天数差。

以下是具体的实现步骤和代码示例。

核心逻辑

  1. 获取上市日期:使用 get_stock_info(stock_list, field=['listed_date']) 获取股票的基础信息。
  2. 获取当前日期:使用 context.blotter.current_dt 获取当前策略运行的时间(注意:不要使用 datetime.datetime.now(),因为在回测中 now() 返回的是服务器系统时间,而不是回测的历史时间)。
  3. 计算时间差:将当前日期与上市日期进行相减,判断天数是否大于等于90天。

策略代码实现

以下是一个完整的策略示例,展示了如何在 before_trading_start 阶段过滤掉次新股。

import datetime

def initialize(context):
    # 示例:以沪深300成分股作为初始股票池
    g.security = get_index_stocks('000300.SS')
    set_universe(g.security)

def before_trading_start(context, data):
    # 获取初始股票池
    all_stocks = g.security
    
    # 调用过滤函数,获取上市超过90天的股票列表
    g.filtered_stocks = filter_new_stocks(context, all_stocks, days=90)
    
    # 打印日志对比数量
    log.info("原始股票数量: %d, 过滤次新股后数量: %d" % (len(all_stocks), len(g.filtered_stocks)))
    
    # 更新当天的股票池(可选,视策略逻辑而定)
    # set_universe(g.filtered_stocks)

def handle_data(context, data):
    # 在这里编写具体的买卖逻辑,仅针对 g.filtered_stocks 操作
    pass

def filter_new_stocks(context, stock_list, days=90):
    """
    过滤上市时间少于指定天数的股票
    :param context: 上下文对象,用于获取当前回测时间
    :param stock_list: 待过滤的股票代码列表
    :param days: 设定的天数阈值,默认90天
    :return: 满足条件的股票列表
    """
    target_list = []
    
    # 获取股票的基础信息,包含上市日期
    # 注意:get_stock_info 返回的是嵌套字典 {'code': {'listed_date': 'yyyy-mm-dd', ...}}
    infos = get_stock_info(stock_list, field=['listed_date'])
    
    # 获取当前策略运行日期的 date 对象
    current_date = context.blotter.current_dt.date()
    
    for stock in stock_list:
        # 获取该股票的具体信息
        stock_data = infos.get(stock)
        
        if stock_data and 'listed_date' in stock_data:
            listed_date_str = stock_data['listed_date']
            
            # 确保日期字符串有效
            if listed_date_str and listed_date_str != '0000-00-00':
                try:
                    # 将字符串转换为 date 对象
                    listed_date = datetime.datetime.strptime(listed_date_str, "%Y-%m-%d").date()
                    
                    # 计算上市天数
                    delta = (current_date - listed_date).days
                    
                    # 如果上市天数大于等于指定天数,则保留
                    if delta >= days:
                        target_list.append(stock)
                except Exception as e:
                    # 日期格式解析出错或其他异常,跳过该股票
                    continue
            else:
                # 如果没有上市日期数据,视情况决定是否保留,这里选择跳过
                continue
        else:
            continue
            
    return target_list

代码关键点解析

  1. get_stock_info: 这是获取静态数据的核心API。必须指定 field=['listed_date'] 才能获取上市日期。
  2. context.blotter.current_dt: 在回测模式下,必须使用此变量来获取“当下的历史时间”。如果使用 Python 原生的 datetime.datetime.now(),在回测2020年的数据时,它会返回2023年(或当前实际年份),导致过滤逻辑失效。
  3. 异常处理: 代码中加入了 try-except 块和对空字符串的检查,防止因为某些股票数据缺失或格式错误导致策略中断。
  4. Python 版本兼容: 代码使用了标准的 datetime 库和基础语法,完全兼容 PTrade 支持的 Python 3.5+ 环境。

Q&A

Q: 为什么在回测中不能使用 datetime.datetime.now() 来计算时间差?
A: datetime.datetime.now() 返回的是代码运行时的服务器系统时间(例如今天是2023年10月1日)。在回测模式下,策略是在模拟过去的时间(例如2018年1月1日)。如果使用 now(),所有股票的上市时间都会被计算为距离2023年很多年,导致无法正确过滤掉回测当时刚上市的新股。必须使用 context.blotter.current_dt

Q: get_stock_info 如果查询不到股票信息会返回什么?
A: 如果查询不到,通常会返回 None 或者该股票代码对应的 value 为空字典。在代码中需要判断 if stock_data 以避免 NoneType 错误。

Q: 如何同时过滤掉 ST 股票和停牌股票?
A: 可以结合 get_stock_status 接口。通常建议先使用 filter_stock_by_status(stock_list, filter_type=["ST", "HALT", "DELISTING"]) 进行初步过滤,然后再将结果传入上面的 filter_new_stocks 函数进行次新股过滤。