自我刻度·记录 文章详情

← 返回主页

Aroon指标趋势交易策略

一、交易策略解释

核心思想

Aroon指标趋势交易策略的核心思想是基于市场趋势形成与持续的时间维度进行分析。与传统的基于价格水平或动量的指标不同,Aroon指标专注于测量自特定周期内最高价/最低价形成以来所经过的时间,从而评估趋势的强度和潜在的趋势变化。

Aroon指标由两个主要组成部分构成:

Aroon Up:测量自特定周期内最高价形成以来所经过的时间

Aroon Down:测量自特定周期内最低价形成以来所经过的时间

该策略基于以下核心假设:强势上涨趋势会频繁创造新高点(Aroon Up接近100),而强势下跌趋势会频繁创造新低点(Aroon Down接近100)。通过观察这两条线的相对位置、交叉点和极端读数,交易者可以识别趋势的初始形成、持续强度以及可能的转变,从而做出相应的交易决策。

理论基础

Aroon指标由技术分析师Tushar Chande于1995年开发,其理论基础建立在趋势识别和趋势持续性的研究上。"Aroon"在梵语中意为"黎明的早期光芒",象征着新趋势的开始。Chande的研究表明,趋势不仅体现在价格的方向上,更体现在新高/新低形成的时间频率上。

Aroon指标的理论贡献在于:

  • 引入时间维度:大多数技术指标关注价格变动的幅度和速度,而Aroon指标独特地引入了时间维度,认为强劲趋势的一个关键特征是快速创造新高或新低的能力。

  • 趋势强度量化:通过将时间因素转化为0-100的标准化范围,提供了对趋势强度的客观量化方法。

  • 趋势周期性研究:提供了识别趋势周期变化的理论框架,是对市场周期理论的重要补充。

策略适用场景

  • 明确趋势市场

  • 中长期时间框架

  • 波动率适中的市场

  • 趋势转换期

    策略原理

    Aroon指标由两个主要分量组成:Aroon Up和Aroon Down,计算公式如下:

    Aroon Up = [(周期长度 - 自最高价形成以来的天数) / 周期长度] × 100
    
    Aroon Down = [(周期长度 - 自最低价形成以来的天数) / 周期长度] × 100
    

    其中:

    • 周期长度为选定的时间期间

    • 自最高/最低价形成以来的天数 是指在当前周期内,最高/最低价出现距今的天数。

    • Aroon指标的值范围为0至100:

      • 值接近100表示最高/最低价是在最近形成的(趋势强劲)

      • 值接近0表示最高/最低价是在较远时间形成的(趋势减弱)

    交易逻辑

    开仓信号:

    该策略使用两种主要的开仓信号:

    • 交叉信号
      • 多头信号:Aroon Up从下方穿越Aroon Down
      • 空头信号:Aroon Down从下方穿越Aroon Up

    代码实现:

    aroon_cross_up = prev.aroon_up < prev.aroon_down and current.aroon_up > current.aroon_down
    aroon_cross_down = prev.aroon_up > prev.aroon_down and current.aroon_up < current.aroon_down
    
    • 强势信号
      • 多头强势:Aroon Up > 75 且 Aroon Down < 25
      • 空头强势:Aroon Down > 75 且 Aroon Up < 25

    代码实现:

    strong_up = current.aroon_up > AROON_UPPER_THRESHOLD and current.aroon_down < AROON_LOWER_THRESHOLD
    strong_down = current.aroon_down > AROON_UPPER_THRESHOLD and current.aroon_up < AROON_LOWER_THRESHOLD
    

    平仓信号:

    平仓信号基于Aroon指标的反向交叉:

    • 平多信号:Aroon Down从下方穿越Aroon Up
    • 平空信号:Aroon Up从下方穿越Aroon Down

    这些反向信号往往代表趋势可能发生转变,是获利了结的好时机。

    止损机制:

    该策略使用基于百分比的固定止损:

    • 止损百分比设定为1.2%(STOP_LOSS_PCT = 1.2)
    • 多头止损:当价格下跌超过入场价格的1.2%时触发
    • 空头止损:当价格上涨超过入场价格的1.2%时触发

    代码实现:

    # 多头止损
    profit_pct = (current_price / entry_price - 1) * 100
    if profit_pct < -STOP_LOSS_PCT:
        # 执行止损
    
    # 空头止损
    profit_pct = (entry_price / current_price - 1) * 100
    if profit_pct < -STOP_LOSS_PCT:
        # 执行止损
    

    回测

    回测初始设置

    • 测试周期: 2023 年 2 月 20 日至 2023 年 5 月 5 日
    • 交易品种: SHFE.au2306
    • 交易频率: 基于日线信号,较低频
    • 参数配置:
      • Aroon周期选择(10天)
        • 短于经典的14天设置,使指标对价格变化更为敏感
        • 适合中期趋势交易,可以更快捕捉趋势转变
        • 在黄金期货交易中,10天周期显示出较好的信号质量
      • 阈值设置(75/25)
        • 设置较高的阈值(>70)可减少虚假信号
        • 75/25的区间在历史回测中显示出较好的信噪比
        • 适合波动性较大的期货市场
      • 止损比例(1.2%)
        • 基于黄金期货的日均波动率(约0.5-0.8%)设定
        • 提供足够的价格呼吸空间,同时控制单笔风险

    回测结果

    Aroon指标趋势交易策略 - 图片 1

    上述回测累计收益走势图

    Aroon指标趋势交易策略 - 图片 2

    完整代码示例

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    __author__ = "Chaos"
    
    from tqsdk import TqApi, TqAuth, TqBacktest, TargetPosTask, BacktestFinished
    import pandas as pd
    from datetime import date
    
    # ===== 全局参数设置 =====
    SYMBOL = "SHFE.au2306"  # 黄金期货合约
    POSITION_SIZE = 30  # 持仓手数
    START_DATE = date(2023, 2, 20)  # 回测开始日期
    END_DATE = date(2023, 5, 5)  # 回测结束日期
    
    # Aroon指标参数
    AROON_PERIOD = 10  # Aroon计算周期
    AROON_UPPER_THRESHOLD = 75  # Aroon上线阈值
    AROON_LOWER_THRESHOLD = 25  # Aroon下线阈值
    
    # 风控参数
    STOP_LOSS_PCT = 1.2  # 止损百分比
    
    # ===== 全局变量 =====
    position = 0  # 当前持仓
    entry_price = 0  # 入场价格
    trades = []  # 交易记录
    
    # ===== 主程序 =====
    print(f"开始回测 {SYMBOL} 的Aroon指标策略...")
    print(f"参数: Aroon周期={AROON_PERIOD}, 上阈值={AROON_UPPER_THRESHOLD}, 下阈值={AROON_LOWER_THRESHOLD}")
    print(f"回测期间: {START_DATE}{END_DATE}")
    
    try:
        # 创建API实例
        api = TqApi(backtest=TqBacktest(start_dt=START_DATE, end_dt=END_DATE),
                    auth=TqAuth("快期账号", "快期密码"))
    
        # 订阅K线数据
        klines = api.get_kline_serial(SYMBOL, 60 * 60 * 24)  # 日K线
        target_pos = TargetPosTask(api, SYMBOL)
    
        # 主循环
        while True:
            api.wait_update()
    
            if api.is_changing(klines.iloc[-1], "datetime"):
                # 确保有足够的数据
                if len(klines) < AROON_PERIOD + 10:
                    continue
                
                # ===== 计算Aroon指标 =====
                # 找出最近N周期内最高价和最低价的位置
                klines['rolling_high'] = klines['high'].rolling(window=AROON_PERIOD).max()
                klines['rolling_low'] = klines['low'].rolling(window=AROON_PERIOD).min()
    
                # 初始化Aroon Up和Aroon Down数组
                aroon_up = []
                aroon_down = []
    
                # 遍历计算每个时间点的Aroon值
                for i in range(len(klines)):
                    if i < AROON_PERIOD - 1:
                        aroon_up.append(0)
                        aroon_down.append(0)
                        continue
                    
                    period_data = klines.iloc[i-AROON_PERIOD+1:i+1]
                    # 明确指定skipna=True来处理NaN值
                    high_idx = period_data['high'].fillna(float('-inf')).argmax()
                    low_idx = period_data['low'].fillna(float('inf')).argmin()
                    
                    days_since_high = i - (i-AROON_PERIOD+1+high_idx)
                    days_since_low = i - (i-AROON_PERIOD+1+low_idx)
                    
                    aroon_up.append(((AROON_PERIOD - days_since_high) / AROON_PERIOD) * 100)
                    aroon_down.append(((AROON_PERIOD - days_since_low) / AROON_PERIOD) * 100)
    
                # 将Aroon值添加到klines
                klines['aroon_up'] = aroon_up
                klines['aroon_down'] = aroon_down
    
                # 计算Aroon Oscillator (可选)
                klines['aroon_osc'] = klines['aroon_up'] - klines['aroon_down']
    
                # 获取当前和前一个周期的数据
                current_price = float(klines.close.iloc[-1])
                current_time = pd.to_datetime(klines.datetime.iloc[-1], unit='ns')
                current_aroon_up = float(klines.aroon_up.iloc[-1])
                current_aroon_down = float(klines.aroon_down.iloc[-1])
                
                prev_aroon_up = float(klines.aroon_up.iloc[-2])
                prev_aroon_down = float(klines.aroon_down.iloc[-2])
    
                # 输出当前指标值,帮助调试
                print(f"当前K线: {current_time.strftime('%Y-%m-%d')}, 价格: {current_price:.2f}")
                print(f"Aroon Up: {current_aroon_up:.2f}, Aroon Down: {current_aroon_down:.2f}")
    
                # ===== 止损检查 =====
                if position != 0 and entry_price != 0:
                    if position > 0:  # 多头止损
                        profit_pct = (current_price / entry_price - 1) * 100
                        if profit_pct < -STOP_LOSS_PCT:
                            print(f"触发止损: 当前价格={current_price}, 入场价={entry_price}, 亏损={profit_pct:.2f}%")
                            target_pos.set_target_volume(0)
                            trades.append({
                                'type': '止损平多',
                                'time': current_time,
                                'price': current_price,
                                'profit_pct': profit_pct
                            })
                            print(f"止损平多: {current_time}, 价格: {current_price:.2f}, 亏损: {profit_pct:.2f}%")
                            position = 0
                            entry_price = 0
                            continue
    
                    elif position < 0:  # 空头止损
                        profit_pct = (entry_price / current_price - 1) * 100
                        if profit_pct < -STOP_LOSS_PCT:
                            print(f"触发止损: 当前价格={current_price}, 入场价={entry_price}, 亏损={profit_pct:.2f}%")
                            target_pos.set_target_volume(0)
                            trades.append({
                                'type': '止损平空',
                                'time': current_time,
                                'price': current_price,
                                'profit_pct': profit_pct
                            })
                            print(f"止损平空: {current_time}, 价格: {current_price:.2f}, 亏损: {profit_pct:.2f}%")
                            position = 0
                            entry_price = 0
                            continue
    
                # ===== 交易信号判断 =====
                # 1. Aroon交叉信号
                aroon_cross_up = prev_aroon_up < prev_aroon_down and current_aroon_up > current_aroon_down
                aroon_cross_down = prev_aroon_up > prev_aroon_down and current_aroon_up < current_aroon_down
    
                # 2. 强势信号
                strong_up = current_aroon_up > AROON_UPPER_THRESHOLD and current_aroon_down < AROON_LOWER_THRESHOLD
                strong_down = current_aroon_down > AROON_UPPER_THRESHOLD and current_aroon_up < AROON_LOWER_THRESHOLD
    
                # ===== 交易决策 =====
                if position == 0:  # 空仓状态
                    # 多头信号
                    if aroon_cross_up or strong_up:
                        position = POSITION_SIZE
                        entry_price = current_price
                        target_pos.set_target_volume(position)
                        signal_type = "交叉" if aroon_cross_up else "强势"
                        trades.append({
                            'type': '开多',
                            'time': current_time,
                            'price': current_price,
                            'signal': signal_type
                        })
                        print(f"开多仓: {current_time}, 价格: {current_price:.2f}, 信号: Aroon {signal_type}")
    
                    # 空头信号
                    elif aroon_cross_down or strong_down:
                        position = -POSITION_SIZE
                        entry_price = current_price
                        target_pos.set_target_volume(position)
                        signal_type = "交叉" if aroon_cross_down else "强势"
                        trades.append({
                            'type': '开空',
                            'time': current_time,
                            'price': current_price,
                            'signal': signal_type
                        })
                        print(f"开空仓: {current_time}, 价格: {current_price:.2f}, 信号: Aroon {signal_type}")
    
                elif position > 0:  # 持有多头
                    # 平多信号
                    if aroon_cross_down:
                        profit_pct = (current_price / entry_price - 1) * 100
                        target_pos.set_target_volume(0)
                        trades.append({
                            'type': '平多',
                            'time': current_time,
                            'price': current_price,
                            'profit_pct': profit_pct
                        })
                        print(f"平多仓: {current_time}, 价格: {current_price:.2f}, 盈亏: {profit_pct:.2f}%")
                        position = 0
                        entry_price = 0
    
                elif position < 0:  # 持有空头
                    # 平空信号
                    if aroon_cross_up:
                        profit_pct = (entry_price / current_price - 1) * 100
                        target_pos.set_target_volume(0)
                        trades.append({
                            'type': '平空',
                            'time': current_time,
                            'price': current_price,
                            'profit_pct': profit_pct
                        })
                        print(f"平空仓: {current_time}, 价格: {current_price:.2f}, 盈亏: {profit_pct:.2f}%")
                        position = 0
                        entry_price = 0
    
    except BacktestFinished as e:
        print("回测结束")
        api.close()

投资思想 · 其他文章 (273)