自我刻度·记录 文章详情

← 返回主页

Qstick趋势策略


一、交易策略解释

核心思想

Qstick趋势指标策略的核心思想是通过分析价格的收盘价与开盘价之间的差异来识别市场趋势和动量。 该指标计算特定周期内"收盘价-开盘价"差值的移动平均线,从而量化市场的看涨或看跌情绪。 当Qstick值为正时,表明市场存在看涨动量;当值为负时,表明市场存在看跌动量。该策略特别关注Qstick指标与零轴的交叉点,将其作为趋势转变的信号。

理论基础

Qstick指标由Tushar Chande开发,基于以下市场观察:

  • 在上升趋势中,收盘价通常高于开盘价

  • 在下降趋势中,收盘价通常低于开盘价

这种价格行为反映了市场参与者的情绪和力量对比。通过将这些差异进行移动平均,Qstick指标能够过滤掉短期噪音,反映更持久的市场趋势。

研究表明,趋势跟踪策略在期货市场中尤其有效,因为商品和金融期货市场常常表现出持续性的价格走势。Qstick指标作为趋势识别工具,能够帮助交易者捕捉这些延续性走势并适时进场交易。

策略适用场景

  • 趋势明显的市场:当市场处于明确的上升或下降趋势中时,Qstick指标能够有效捕捉趋势转变点。

  • 中长期交易:由于采用移动平均平滑处理,该策略更适合日线或更长时间周期的交易,而非短线交易。

  • 波动性适中的品种:如主要商品期货、股指期货等,相比极端高波动或低波动的品种更为适用。

  • 流动性较好的市场:确保能够以合理价格迅速执行交易指令。

    策略原理

    Qstick指标的计算方法:

    def calculate_qstick(open_prices, close_prices, period):
        """计算Qstick指标"""
        # 计算收盘价与开盘价的差值
        diff = close_prices - open_prices
        # 计算移动平均
        qstick = diff.rolling(window=period).mean()
        return qstick
    

    其中:

    • 计算每根K线的收盘价减去开盘价的差值

    • 对这些差值序列取n周期的简单移动平均值

    • 最终得到的Qstick指标反映了一段时间内收盘价相对开盘价的平均偏离方向和幅度

    本策略使用10周期的Qstick指标,此参数设置旨在平衡信号灵敏度与稳定性。

    此外,还使用了两个辅助指标加强交易信号的质量:

    1. SMA指标:8周期简单移动平均线,用于确认价格所处的大方向

    2. ATR指标:14周期平均真实波幅,用于设置动态止损位置

    交易逻辑

    开仓信号:

    • 多头信号:Qstick从负值向上穿越零轴,价格在SMA上方
    if previous_qstick < 0 and current_qstick > 0 and current_price > current_price_sma:
        current_direction = 1
        target_pos.set_target_volume(POSITION_SIZE)
        entry_price = current_price
        entry_date = current_datetime
        # 设置止损价格
        stop_loss_price = entry_price - STOP_LOSS_MULTIPLIER * current_atr
    
    • 空头信号:Aroon Down从下方穿越Aroon Up
    elif previous_qstick > 0 and current_qstick < 0 and current_price < current_price_sma:
        current_direction = -1
        target_pos.set_target_volume(-POSITION_SIZE)
        entry_price = current_price
        entry_date = current_datetime
        # 设置止损价格
        stop_loss_price = entry_price + STOP_LOSS_MULTIPLIER * current_atr
    

    开仓后,系统会立即设置基于ATR的动态止损位置,使用2倍ATR值作为止损距离。

    平仓信号:

    • 止损平仓:价格触及预设止损位置时强制平仓
    # 多头止损
    if current_price <= stop_loss_price:
        # 平仓逻辑
    
    # 空头止损
    if current_price >= stop_loss_price:
        # 平仓逻辑
    
    • 反向信号平仓:当Qstick指标产生反向穿越零轴信号时平仓
    # 多头反向信号平仓
    elif previous_qstick > 0 and current_qstick < 0:
        # 平仓逻辑
    
    # 空头反向信号平仓
    elif previous_qstick < 0 and current_qstick > 0:
        # 平仓逻辑
    
    • 时间止损:当持仓时间超过5天时强制平仓
    # 时间止损
    elif holding_days >= MAX_HOLDING_DAYS:
        # 平仓逻辑
    

    回测

    回测初始设置

    • 测试周期: 2022 年 8 月 1 日 - 2023 年 1 月 30 日
    • 交易品种: CFFEX.IC2303
    • 初始资金: 1000万元

    回测结果

    Qstick趋势策略 - 图片 1

    上述回测累计收益走势图

    Qstick趋势策略 - 图片 2

    代码

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    __author__ = "Chaos"
    
    from datetime import date
    import pandas as pd
    from tqsdk import TqApi, TqAuth, TqBacktest, TargetPosTask, BacktestFinished
    from tqsdk.ta import ATR
    
    # ===== 全局参数设置 =====
    SYMBOL = "CFFEX.IC2303"  # 中证500指数期货
    POSITION_SIZE = 30  # 持仓手数
    START_DATE = date(2022, 8, 1)  # 回测开始日期
    END_DATE = date(2023, 1, 30)  # 回测结束日期
    
    # Qstick指标参数
    QSTICK_PERIOD = 10  # Qstick周期
    SMA_PERIOD = 8  # 价格SMA周期,用于确认趋势
    
    # 风控参数
    ATR_PERIOD = 14  # ATR计算周期
    STOP_LOSS_MULTIPLIER = 2.0  # 止损ATR倍数
    MAX_HOLDING_DAYS = 5  # 最大持仓天数
    
    # ===== 全局变量 =====
    current_direction = 0  # 当前持仓方向:1=多头,-1=空头,0=空仓
    entry_price = 0  # 开仓价格
    stop_loss_price = 0  # 止损价格
    entry_date = None  # 开仓日期
    
    
    # ===== Qstick指标计算函数 =====
    def calculate_qstick(open_prices, close_prices, period):
        """计算Qstick指标"""
        # 计算收盘价与开盘价的差值
        diff = close_prices - open_prices
        # 计算移动平均
        qstick = diff.rolling(window=period).mean()
        return qstick
    
    
    # ===== 策略开始 =====
    print("开始运行Qstick趋势指标期货策略...")
    
    # 创建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)  # 日线数据
    
    # 创建目标持仓任务
    target_pos = TargetPosTask(api, SYMBOL)
    
    try:
        while True:
            # 等待更新
            api.wait_update()
    
            # 如果K线有更新
            if api.is_changing(klines.iloc[-1], "datetime"):
                # 确保有足够的数据计算指标
                if len(klines) < max(QSTICK_PERIOD, SMA_PERIOD, ATR_PERIOD) + 5:
                    continue
    
                # 计算Qstick指标
                klines['qstick'] = calculate_qstick(klines.open, klines.close, QSTICK_PERIOD)
    
                # 计算价格SMA,用于确认趋势
                klines['price_sma'] = klines.close.rolling(window=SMA_PERIOD).mean()
    
                # 计算ATR用于设置止损
                atr_data = ATR(klines, ATR_PERIOD)
    
                # 获取最新数据
                current_price = float(klines.close.iloc[-1])
                current_datetime = pd.to_datetime(klines.datetime.iloc[-1], unit='ns')
                current_qstick = float(klines.qstick.iloc[-1])
                previous_qstick = float(klines.qstick.iloc[-2])
                current_price_sma = float(klines.price_sma.iloc[-1])
                current_atr = float(atr_data.atr.iloc[-1])
    
                # 输出调试信息
                print(f"日期: {current_datetime.strftime('%Y-%m-%d')}, 价格: {current_price:.2f}")
                print(f"Qstick: {current_qstick:.4f}")
    
                # ===== 交易逻辑 =====
    
                # 空仓状态 - 寻找开仓机会
                if current_direction == 0:
                    # 多头开仓条件:Qstick从负值向上穿越零轴,价格在SMA上方
                    if previous_qstick < 0 and current_qstick > 0 and current_price > current_price_sma:
                        current_direction = 1
                        target_pos.set_target_volume(POSITION_SIZE)
                        entry_price = current_price
                        entry_date = current_datetime
    
                        # 设置止损价格
                        stop_loss_price = entry_price - STOP_LOSS_MULTIPLIER * current_atr
    
                        print(f"多头开仓: 价格={entry_price}, 止损={stop_loss_price:.2f}")
    
                    # 空头开仓条件:Qstick从正值向下穿越零轴,价格在SMA下方
                    elif previous_qstick > 0 and current_qstick < 0 and current_price < current_price_sma:
                        current_direction = -1
                        target_pos.set_target_volume(-POSITION_SIZE)
                        entry_price = current_price
                        entry_date = current_datetime
    
                        # 设置止损价格
                        stop_loss_price = entry_price + STOP_LOSS_MULTIPLIER * current_atr
    
                        print(f"空头开仓: 价格={entry_price}, 止损={stop_loss_price:.2f}")
    
                # 多头持仓 - 检查平仓条件
                elif current_direction == 1:
                    # 计算持仓天数
                    holding_days = (current_datetime - entry_date).days
    
                    # 1. 止损条件:价格低于止损价格
                    if current_price <= stop_loss_price:
                        profit_pct = (current_price - entry_price) / entry_price * 100
                        target_pos.set_target_volume(0)
                        current_direction = 0
                        print(f"多头止损平仓: 价格={current_price}, 盈亏={profit_pct:.2f}%, 持仓天数={holding_days}")
    
                    # 2. 反向信号平仓:Qstick从正值向下穿越零轴
                    elif previous_qstick > 0 and current_qstick < 0:
                        profit_pct = (current_price - entry_price) / entry_price * 100
                        target_pos.set_target_volume(0)
                        current_direction = 0
                        print(f"多头信号平仓: 价格={current_price}, 盈亏={profit_pct:.2f}%, 持仓天数={holding_days}")
    
                    # 3. 时间止损:持仓时间过长
                    elif holding_days >= MAX_HOLDING_DAYS:
                        profit_pct = (current_price - entry_price) / entry_price * 100
                        target_pos.set_target_volume(0)
                        current_direction = 0
                        print(f"多头时间平仓: 价格={current_price}, 盈亏={profit_pct:.2f}%, 持仓天数={holding_days}")
    
                # 空头持仓 - 检查平仓条件
                elif current_direction == -1:
                    # 计算持仓天数
                    holding_days = (current_datetime - entry_date).days
    
                    # 1. 止损条件:价格高于止损价格
                    if current_price >= stop_loss_price:
                        profit_pct = (entry_price - current_price) / entry_price * 100
                        target_pos.set_target_volume(0)
                        current_direction = 0
                        print(f"空头止损平仓: 价格={current_price}, 盈亏={profit_pct:.2f}%, 持仓天数={holding_days}")
    
                    # 2. 反向信号平仓:Qstick从负值向上穿越零轴
                    elif previous_qstick < 0 and current_qstick > 0:
                        profit_pct = (entry_price - current_price) / entry_price * 100
                        target_pos.set_target_volume(0)
                        current_direction = 0
                        print(f"空头信号平仓: 价格={current_price}, 盈亏={profit_pct:.2f}%, 持仓天数={holding_days}")
    
                    # 3. 时间止损:持仓时间过长
                    elif holding_days >= MAX_HOLDING_DAYS:
                        profit_pct = (entry_price - current_price) / entry_price * 100
                        target_pos.set_target_volume(0)
                        current_direction = 0
                        print(f"空头时间平仓: 价格={current_price}, 盈亏={profit_pct:.2f}%, 持仓天数={holding_days}")
    
    except BacktestFinished as e:
        print("回测结束")
        api.close()

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