🚀 AI 一键生成 joinquant 策略代码

JoinQuant 平台 AO 指标策略编程指南(附 Python 源码)

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

问题描述

请帮我编写一个使用AO(Awesome Oscillator)指标的交易策略。

解决方案

这是一个基于 Awesome Oscillator (AO) 指标的交易策略。

策略原理

Awesome Oscillator (AO) 是一个动量指标,用于衡量近期动量与长期动量的差异。

  1. 计算公式
    • 中点价格 (Median Price) = (最高价 + 最低价) / 2
    • AO = SMA(中点价格, 5) - SMA(中点价格, 34)
    • 其中 SMA 为简单移动平均线。
  2. 交易逻辑(零轴穿越策略)
    • 买入信号:当 AO 线从下向上穿越零轴时(即上一个周期的 AO < 0 且 当前周期的 AO > 0),视为看涨信号,全仓买入。
    • 卖出信号:当 AO 线从上向下穿越零轴时(即上一个周期的 AO > 0 且 当前周期的 AO < 0),视为看跌信号,清仓卖出。

策略代码

以下是完整的 JoinQuant 策略代码:

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

def initialize(context):
    """
    初始化函数,设定基准、手续费、滑点等
    """
    # 设定沪深300作为基准
    set_benchmark('000300.XSHG')
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    
    # 过滤掉order系列API产生的比error级别低的log
    log.set_level('order', 'error')
    
    # 设定要操作的股票,这里以平安银行(000001.XSHE)为例
    # 您可以修改为一个列表,例如 g.security_list = get_index_stocks('000300.XSHG')
    g.security_list = ['000001.XSHE']
    
    # 设定AO指标的参数
    g.short_period = 5
    g.long_period = 34
    
    # 设定交易费用
    set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
    
    # 每天开盘时运行策略
    run_daily(trade_logic, 'every_bar')

def trade_logic(context):
    """
    每日交易逻辑
    """
    for security in g.security_list:
        # 获取足够的历史数据来计算SMA34
        # 我们需要计算当前的AO和前一日的AO,所以至少需要 long_period + 2 天的数据
        # 为了保险起见,获取50天的数据
        data = attribute_history(security, 50, '1d', ['high', 'low', 'close'])
        
        # 如果数据不足,跳过
        if len(data) < g.long_period + 2:
            continue
            
        # 1. 计算中点价格 (Median Price)
        # Median Price = (High + Low) / 2
        median_price = (data['high'] + data['low']) / 2
        
        # 2. 计算 SMA5 和 SMA34
        sma_5 = median_price.rolling(window=g.short_period).mean()
        sma_34 = median_price.rolling(window=g.long_period).mean()
        
        # 3. 计算 AO 指标
        ao = sma_5 - sma_34
        
        # 获取当前和前一天的AO值
        # iloc[-1] 是当前(最新)的AO值(基于昨天收盘数据,因为是在开盘运行)
        # iloc[-2] 是前一天的AO值
        current_ao = ao.iloc[-1]
        previous_ao = ao.iloc[-2]
        
        # 检查是否包含NaN值(刚开始计算时会有NaN)
        if np.isnan(current_ao) or np.isnan(previous_ao):
            continue
            
        # 获取当前持仓
        position = context.portfolio.positions[security]
        
        # 4. 交易信号判断
        
        # 买入信号:AO 上穿零轴 (前值 < 0, 当前值 > 0)
        if previous_ao < 0 and current_ao > 0:
            # 如果没有持仓,则买入
            if position.closeable_amount == 0:
                # 使用可用资金平均分配买入(如果是多只股票)
                cash = context.portfolio.available_cash / len(g.security_list)
                order_value(security, cash)
                log.info("买入信号触发: %s, Prev_AO: %.4f, Curr_AO: %.4f" % (security, previous_ao, current_ao))
        
        # 卖出信号:AO 下穿零轴 (前值 > 0, 当前值 < 0)
        elif previous_ao > 0 and current_ao < 0:
            # 如果有持仓,则卖出
            if position.closeable_amount > 0:
                order_target(security, 0)
                log.info("卖出信号触发: %s, Prev_AO: %.4f, Curr_AO: %.4f" % (security, previous_ao, current_ao))

常见问题 (Q&A)

Q: 为什么使用 attribute_history 获取数据?
A: AO 指标需要基于过去一段时间的最高价和最低价来计算中点价格。attribute_history 是 JoinQuant 中获取历史行情数据最常用的 API,能够方便地获取 DataFrame 格式的数据进行向量化计算。

Q: 代码中的 run_daily(trade_logic, 'every_bar') 是什么意思?
A: 这表示策略按天频率运行。trade_logic 函数会在每个交易日开盘时被调用一次。此时获取的历史数据(attribute_history)默认是不包含当天的(即截止到昨天收盘),这符合回测逻辑,避免了未来函数。

Q: 如何修改策略以操作多只股票?
A: 在 initialize 函数中,修改 g.security_list 即可。例如,若要操作沪深300成分股,可以将代码改为:g.security_list = get_index_stocks('000300.XSHG')。代码中的资金分配逻辑已经做了简单的平均分配处理。

Q: AO 指标除了零轴穿越还有其他用法吗?
A: 是的,AO 还有“碟形信号”(Saucer)和“双峰背离”(Twin Peaks)等用法。本策略为了保持简洁和稳健,仅实现了最核心的零轴穿越(动量反转)逻辑。