🚀 AI 一键生成 joinquant 策略代码

JoinQuant 策略实战:利用 PSY 心理线捕捉市场超买超卖

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

问题描述

请编写一个基于 PSY 心理线指标的交易策略

解决方案

这是一个基于 PSY(Psychological Line,心理线) 指标的量化交易策略。

策略原理

PSY 指标主要用于研究投资者对股市涨跌产生心理波动的轨迹。它通过计算一段时间内股价上涨天数占总天数的比例,来判断市场的超买或超卖状态。

  • 计算公式:$PSY(N) = \frac{N \text{日内上涨天数}}{N} \times 100$
  • 参数设置:通常 $N$ 取 12 或 24。
  • 交易逻辑
    • 买入信号:当 PSY 值低于 25(或 20),表示市场处于超卖区域,投资者恐慌过度,可能出现反弹,执行买入。
    • 卖出信号:当 PSY 值高于 75(或 80),表示市场处于超买区域,投资者情绪过热,可能出现回调,执行卖出。

策略代码实现

以下代码可在聚宽(JoinQuant)的回测环境中直接运行。

# -*- coding: utf-8 -*-
import jqdata
import numpy as np

def initialize(context):
    """
    初始化函数,设定基准、手续费、滑点及策略参数
    """
    # 设定沪深300作为基准
    set_benchmark('000300.XSHG')
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    
    # 设置交易手续费:买入万三,卖出万三加千一印花税
    set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
    
    # 设定要操作的标的(这里以平安银行为例,也可以换成ETF如 510300.XSHG)
    g.security = '000001.XSHE'
    
    # PSY指标参数 N
    g.N = 12
    
    # 策略阈值
    g.buy_threshold = 25  # PSY低于此值买入
    g.sell_threshold = 75 # PSY高于此值卖出
    
    # 每天开盘时运行策略
    run_daily(market_open, time='open')

def market_open(context):
    """
    每日交易逻辑
    """
    security = g.security
    
    # 获取过去 N+1 天的收盘价数据
    # 我们需要 N 个变动数据,所以需要 N+1 个历史收盘价来计算涨跌
    hist_data = attribute_history(security, g.N + 1, '1d', ['close'], skip_paused=True)
    
    # 如果数据不足(例如刚上市),则不操作
    if len(hist_data) < g.N + 1:
        return
    
    close_prices = hist_data['close'].values
    
    # 计算上涨天数
    up_days = 0
    for i in range(1, len(close_prices)):
        # 如果今天的收盘价 > 昨天的收盘价,记为上涨
        if close_prices[i] > close_prices[i-1]:
            up_days += 1
            
    # 计算 PSY 值
    psy_value = (up_days / g.N) * 100
    
    # 获取当前账户资金和持仓情况
    curr_position = context.portfolio.positions[security].closeable_amount
    available_cash = context.portfolio.available_cash
    
    # 打印日志方便调试
    # log.info(f"日期: {context.current_dt.date()}, PSY值: {psy_value:.2f}")
    
    # 交易逻辑
    # 1. 超卖区域(PSY <= 25)且空仓 -> 全仓买入
    if psy_value <= g.buy_threshold and curr_position == 0:
        log.info(f"PSY值为 {psy_value:.2f},进入超卖区,执行买入")
        order_value(security, available_cash)
        
    # 2. 超买区域(PSY >= 75)且持仓 -> 清仓卖出
    elif psy_value >= g.sell_threshold and curr_position > 0:
        log.info(f"PSY值为 {psy_value:.2f},进入超买区,执行卖出")
        order_target(security, 0)
        
    # 记录曲线,方便在回测图中查看 PSY 走势
    record(PSY=psy_value)

代码解析

  1. 数据获取:使用 attribute_history 获取过去 N+1 天的收盘价。为什么是 N+1?因为判断第 1 天是否上涨需要参考第 0 天的价格。
  2. 指标计算:通过循环对比每日收盘价与前一日收盘价,统计上涨天数,进而算出 PSY 值。
  3. 交易执行
    • 当 PSY $\le$ 25 时,认为市场情绪悲观,属于反向操作的买入时机。
    • 当 PSY $\ge$ 75 时,认为市场情绪亢奋,属于获利了结的卖出时机。
  4. 可视化:使用 record(PSY=psy_value) 可以在回测结果页面的图表中看到 PSY 指标的历史走势,便于分析策略有效性。

Q&A

Q: PSY 指标适合什么类型的市场?
A: PSY 指标在震荡市中表现较好,能够捕捉到情绪的极值点进行高抛低吸。在单边的大牛市或大熊市中,PSY 可能会出现“钝化”现象(例如在大牛市中 PSY 长期高于 75),导致过早卖出或过早抄底,因此建议结合均线(MA)或趋势指标(MACD)一起使用。

Q: 如何调整策略的灵敏度?
A: 可以通过调整参数 g.N 来改变灵敏度。

  • 减小 g.N(如改为 6):指标更敏感,交易信号更频繁,但假信号也更多。
  • 增大 g.N(如改为 24):指标更平滑,信号更稳定,但可能滞后。

Q: 代码中的 attribute_history 包含当天的数据吗?
A: 在 run_daily 设置为 time='open'(开盘运行)时,attribute_history 获取的是截止到昨天收盘的历史数据,不包含今天的数据。这是为了避免“未来函数”,即在开盘时我们只能利用昨天及以前的数据来做决策。

Q: 这个策略可以用于多只股票吗?
A: 上述代码是针对单只股票设计的。如果要用于多只股票,需要将 g.security 改为股票列表,并在 market_open 函数中增加一个 for 循环遍历股票列表,分别计算每只股票的 PSY 并独立下单。