🚀 AI 一键生成 ptrade 策略代码

如何用 PTrade 编写行业轮动策略?(附 get_industry_stocks 使用方法)

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

问题描述

请帮我编写一个获取特定行业所有股票并进行交易的策略。

解决方案

这是一个基于PTrade API编写的策略示例。该策略的核心功能是获取指定行业的所有成分股,剔除ST和停牌股票后,按照等权重(即每只股票买入金额相同)进行买入调仓。

策略说明

  1. 行业选择:在 initialize 中设置行业代码(例如:J66000.XBHS 代表货币金融服务/银行业)。
  2. 股票筛选:在 before_trading_start 中获取该行业所有股票,并使用 filter_stock_by_status 自动过滤掉ST、停牌和退市的股票。
  3. 交易逻辑:在 handle_data 中,计算当前账户总资产,除以股票数量得到每只股票的目标持仓金额,使用 order_target_value 进行调仓。

PTrade 策略代码

def initialize(context):
    """
    初始化函数,设置策略参数
    """
    # 1. 设置要交易的行业代码
    # 示例使用 'J66000.XBHS' (货币金融服务/银行),您可以根据文档附录修改为其他行业
    g.industry_code = 'J66000.XBHS'
    
    # 2. 设置回测费用(可选,实盘会自动忽略)
    # 设置佣金为万分之三,最低5元
    set_commission(commission_ratio=0.0003, min_commission=5.0, type="STOCK")
    
    # 3. 打印日志
    log.info("策略初始化完成,目标行业: %s" % g.industry_code)

def before_trading_start(context, data):
    """
    盘前处理函数,每日开盘前运行
    """
    # 1. 获取指定行业的成分股列表
    # 注意:get_industry_stocks 获取的是当下的数据,回测中存在未来函数风险,但在实盘中是准确的
    industry_stocks = get_industry_stocks(g.industry_code)
    
    if not industry_stocks:
        log.warning("未获取到行业 %s 的成分股,请检查代码是否正确" % g.industry_code)
        g.security = []
        return

    # 2. 过滤掉 ST、停牌、退市的股票
    # filter_stock_by_status 是PTrade内置的高效过滤函数
    # 过滤类型: "ST" (ST股), "HALT" (停牌), "DELISTING" (退市)
    g.security = filter_stock_by_status(industry_stocks, ["ST", "HALT", "DELISTING"])
    
    # 3. 设置股票池
    if len(g.security) > 0:
        set_universe(g.security)
        log.info("今日待交易股票数量: %d" % len(g.security))
    else:
        log.warning("过滤后无可用股票")

def handle_data(context, data):
    """
    盘中运行函数,执行交易逻辑
    """
    # 如果没有股票池,直接返回
    if not g.security:
        return

    # 获取当前股票池数量
    stock_count = len(g.security)
    
    # 获取账户总资产 (现金 + 持仓市值)
    total_value = context.portfolio.portfolio_value
    
    # 计算每只股票的目标持仓金额 (等权重分配)
    # 注意:如果资金过少或股票过多,可能导致每只股票分配金额不足一手(100股)
    target_value_per_stock = total_value / stock_count
    
    # 遍历股票池进行交易
    for stock in g.security:
        # 检查该股票是否有行情数据(避免数据缺失导致报错)
        if stock in data:
            # 使用 order_target_value 调整持仓到目标金额
            # 如果持有金额少于目标,会买入;如果多于目标,会卖出;如果没有,会建仓
            order_target_value(stock, target_value_per_stock)
            
            # 简单的日志记录 (可选,为了减少日志量,建议仅在特定条件下打印)
            # log.info("调整 %s 持仓至 %.2f 元" % (stock, target_value_per_stock))

def after_trading_end(context, data):
    """
    盘后处理函数
    """
    log.info("今日交易结束,当前总资产: %.2f" % context.portfolio.portfolio_value)

如何修改行业代码

您可以参考 PTrade 文档中的《附录:行业列表》修改 g.industry_code。以下是一些常用行业代码示例:

  • J66000.XBHS: 货币金融服务(银行)
  • J67000.XBHS: 资本市场服务(证券)
  • C27000.XBHS: 医药制造业
  • I65000.XBHS: 软件和信息技术服务业
  • C39000.XBHS: 计算机、通信和其他电子设备制造业
  • A01000.XBHS: 农业

注意事项

  1. 资金量与股票数量:如果选择的行业包含几百只股票(如制造业),而您的资金量较小,计算出的单只股票买入金额可能不足一手(100股),导致无法成交。建议选择细分行业或增加资金。
  2. 未来函数get_industry_stocks 获取的是当前最新的成分股。在回测几年前的数据时,它返回的仍然是今天的成分股列表(即包含当时未上市或不属于该行业的股票),这属于“未来函数”。但在实盘交易中,这是完全正确的用法。
  3. Python版本:代码已遵循 Python 3.5 兼容性规范(未使用 f-string)。

Q&A

Q: 如何限制最大持仓股票数量?
A: 可以在 before_trading_start 中对 g.security 列表进行切片。例如,只取前10只股票:g.security = g.security[:10]

Q: 为什么回测时 get_industry_stocks 获取的股票和历史不一样?
A: PTrade 的 get_industry_stocks 返回的是当前时刻的行业成分股,不包含历史变动信息。如果在回测中需要严格的历史成分股,通常需要使用指数成分股接口 get_index_stocks(如沪深300行业指数)并指定 date 参数。

Q: 如何将交易频率改为每周调仓一次?
A: 可以在 handle_data 中增加日期判断,或者使用 run_daily 配合计数器逻辑,甚至直接在 initialize 中使用 run_weekly(如果平台支持)来控制调仓频率。最简单的方法是在 handle_data 开头判断 context.blotter.current_dt 是否为周五。