🚀 AI 一键生成 ptrade 策略代码

PTrade 策略进阶:如何高效编写多股票、多资产的投资组合策略?

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

问题描述

如何编写一个同时交易多只股票的策略,并根据市场情况调整每只股票的仓位?

解决方案

这是一个非常实用的量化交易需求。要在 PTrade 中实现同时交易多只股票并根据市场情况调整仓位,我们需要设计一个策略框架,包含以下核心逻辑:

  1. 股票池设置:定义一组要监控和交易的股票。
  2. 大盘风控(市场环境判断):引入一个基准指数(如沪深300),当指数走弱时降低仓位或空仓,走强时进行交易。
  3. 个股择时:对股票池中的每一只股票进行独立的技术分析(如均线判断)。
  4. 动态调仓:根据符合买入条件的股票数量,动态分配资金(例如等权重分配)。

下面是一个完整的 PTrade 策略代码示例。该策略实现了**“大盘择时 + 个股均线轮动 + 资金等权分配”**的逻辑。

策略逻辑说明

  • 核心思想:顺势而为,大盘不好不操作,个股走坏就剔除。
  • 大盘判断:使用沪深300指数(000300.SS)作为风向标。如果指数低于20日均线,视为市场环境恶劣,清仓防守。
  • 个股判断:如果大盘环境安全,则检查股票池中的股票。如果个股价格高于其20日均线,则买入/持有;否则卖出。
  • 仓位管理:将当前总资产平分给所有符合买入条件的股票(等权重模型)。

PTrade 策略代码

# 导入必要的库 (PTrade环境中通常不需要显式导入numpy/pandas,但为了代码提示可写)
import numpy as np

def initialize(context):
    """
    初始化函数,设置股票池、参数和全局变量
    """
    # 1. 设定要操作的股票池 (示例:几只科技和消费龙头)
    g.security_list = ['600519.SS', '000858.SZ', '601318.SS', '600036.SS', '002594.SZ']
    
    # 2. 设定大盘基准指数 (沪深300)
    g.benchmark_index = '000300.SS'
    
    # 3. 设定均线周期参数
    g.ma_days = 20
    
    # 4. 设置股票池 (必须步骤)
    set_universe(g.security_list)
    
    # 5. 开启日志输出
    log.info("策略初始化完成,股票池数量: %d" % len(g.security_list))

def handle_data(context, data):
    """
    核心交易逻辑,按频率运行 (日线或分钟线)
    """
    # ---------------------------------------------------
    # 第一步:大盘风控 (市场环境判断)
    # ---------------------------------------------------
    # 获取大盘指数过去 N+1 天的历史收盘价
    index_hist = get_history(g.ma_days + 1, '1d', 'close', g.benchmark_index)
    
    # 如果数据不足,直接返回
    if len(index_hist) < g.ma_days + 1:
        return
    
    # 计算大盘均线 (不包含当天的前N天均值)
    index_close = index_hist['close'].values
    index_ma = index_close[:-1].mean()
    index_current_price = index_close[-1]
    
    # 判断大盘趋势
    market_is_safe = index_current_price > index_ma
    
    if not market_is_safe:
        log.info("大盘跌破%d日均线,市场环境恶劣,执行清仓风控。" % g.ma_days)
        # 遍历持仓,全部卖出
        for stock in context.portfolio.positions.keys():
            order_target(stock, 0)
        return  # 结束本周期运行

    # ---------------------------------------------------
    # 第二步:个股筛选 (选出符合条件的股票)
    # ---------------------------------------------------
    buy_list = []
    
    for stock in g.security_list:
        # 获取个股历史数据
        # 注意:这里为了演示清晰,在循环中获取数据。
        # 实际生产中,若股票池很大,建议一次性获取所有股票数据以提高效率。
        stock_hist = get_history(g.ma_days + 1, '1d', 'close', stock)
        
        if len(stock_hist) < g.ma_days + 1:
            continue
            
        stock_close = stock_hist['close'].values
        stock_ma = stock_close[:-1].mean()
        stock_current_price = stock_close[-1]
        
        # 如果个股价格在均线之上,加入待买入列表
        if stock_current_price > stock_ma:
            buy_list.append(stock)
    
    # ---------------------------------------------------
    # 第三步:资金分配与调仓 (根据市场情况调整仓位)
    # ---------------------------------------------------
    # 如果没有符合条件的股票,清仓
    if len(buy_list) == 0:
        log.info("没有符合条件的个股,清仓观望。")
        for stock in context.portfolio.positions.keys():
            order_target(stock, 0)
        return

    # 计算每只股票的目标市值
    # 逻辑:总资产 / 待买入股票数量 = 每只股票应持有的金额
    total_value = context.portfolio.portfolio_value
    target_value_per_stock = total_value / len(buy_list)
    
    log.info("符合买入条件的股票: %s, 每只目标市值: %.2f" % (str(buy_list), target_value_per_stock))
    
    # 开始调仓
    # 1. 先卖出:不在buy_list中的持仓股票需要卖出
    for stock in context.portfolio.positions.keys():
        if stock not in buy_list:
            order_target(stock, 0)
            log.info("卖出不符合条件的股票: %s" % stock)
            
    # 2. 后买入/调整:在buy_list中的股票,调整到目标市值
    for stock in buy_list:
        # order_target_value 会自动计算买入或卖出的数量,使持仓市值达到 target_value_per_stock
        # 如果资金不足,系统会自动调整为最大可买数量
        order_target_value(stock, target_value_per_stock)

代码关键点解析

  1. get_history 的使用

    • 我们获取 g.ma_days + 1 天的数据,是为了计算截止到昨天的均线,并与今天的最新价(或收盘价)进行对比。
    • index_close[:-1].mean() 计算的是前N天的均值,避免包含当前未收盘的价格导致信号闪烁(如果是回测,这代表昨日均线)。
  2. order_target_value 的优势

    • 这是多股策略中最核心的函数。
    • 你不需要计算“我要买多少股”,只需要告诉系统“我希望这只股票现在的持仓市值是多少”。
    • 如果当前持仓为0,它会买入;如果当前持仓市值低于目标,它会加仓;如果高于目标(例如股价大涨导致仓位过重),它会减仓。这自动实现了再平衡(Rebalancing)
  3. 风险控制

    • 代码优先判断大盘指数。这是一种典型的“自上而下”的策略思路,能有效避免在系统性风险(股灾)来临时频繁止损。
  4. 兼容性

    • 代码避免了 Python 3.6+ 的 f-string 语法(如 f"text {var}"),改用 % 格式化,确保在 PTrade 旧版本 Python 环境中也能稳定运行。

如何在 PTrade 中运行

  1. 新建一个策略,选择“股票”类型。
  2. 将上述代码复制到代码编辑区。
  3. 在右侧设置回测参数(如资金 1,000,000,频率选择“日线”)。
  4. 点击“运行回测”即可看到多只股票同时交易的效果。

Q&A: 常见问题解答

Q: 如何修改股票池?
A:initialize 函数中,修改 g.security_list 列表即可。你可以填入任意你关注的股票代码(注意后缀 .SS 代表上交所,.SZ 代表深交所)。

Q: 为什么使用 order_target_value 而不是 order
A: order 只是简单的按数量买卖。在多股策略中,股价各不相同(有的10元,有的100元),如果按固定数量买入,会导致高价股占用过多资金。order_target_value 可以按金额等权分配,是管理多只股票仓位的最佳工具。

Q: 这个策略可以用于分钟级别回测吗?
A: 可以。如果在回测设置中选择“分钟”频率,handle_data 会每分钟执行一次。但要注意,均线计算逻辑可能需要调整(例如获取分钟级别的历史数据),且高频交易会增加手续费成本。对于均线策略,通常建议在日线级别运行。

Q: 如何增加止损逻辑?
A: 可以在 handle_data 的循环中加入判断。例如,获取持仓成本 context.portfolio.positions[stock].cost_basis,如果 (current_price - cost_basis) / cost_basis < -0.10 (亏损10%),则强制执行 order_target(stock, 0)