🚀 AI 一键生成 qmt 策略代码

结合价格与成交量的趋势策略:Force Index 在 QMT 中的实现

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

问题描述

如何编写强力指数 Force Index 的交易策略?

解决方案

强力指数 (Force Index) 交易策略

强力指数(Force Index,简称 FI)是由亚历山大·埃尔德(Alexander Elder)博士开发的指标,用于衡量价格变动背后的力量。它结合了价格变动的方向、幅度和成交量三个要素。

策略原理

强力指数的基本公式为:
$$FI = (今日收盘价 - 昨日收盘价) \times 今日成交量$$

在实际交易中,通常会对原始的 FI 进行平滑处理(通常使用 EMA)。

本策略逻辑如下:

  1. 计算指标:计算 13 周期指数移动平均(EMA)的强力指数。
  2. 买入信号:当 13日 EMA Force Index 从下向上穿过 0 轴时,表明买方力量占据主导,趋势可能转强,执行买入。
  3. 卖出信号:当 13日 EMA Force Index 从上向下穿过 0 轴时,表明卖方力量占据主导,趋势可能转弱,执行卖出(清仓)。

QMT 策略代码实现

以下是基于 QMT Python API 的完整策略代码。代码包含了数据获取、指标计算和交易信号执行。

# -*- coding: gbk -*-
import pandas as pd
import numpy as np

def init(ContextInfo):
    """
    初始化函数,设定策略参数和账户
    """
    # 设定交易账号,请替换为您的真实资金账号
    ContextInfo.account_id = '6000000000' 
    ContextInfo.set_account(ContextInfo.account_id)
    
    # 设定标的股票,这里以浦发银行为例
    ContextInfo.stock_code = '600000.SH'
    
    # 设定强力指数的平滑周期,通常短线用2,中线用13
    ContextInfo.fi_period = 13
    
    # 设定取数数量,保证有足够的数据计算EMA
    ContextInfo.data_count = 100
    
    # 设定股票池
    ContextInfo.set_universe([ContextInfo.stock_code])

def handlebar(ContextInfo):
    """
    K线周期运行函数
    """
    # 获取当前周期
    period = ContextInfo.period
    
    # 获取当前正在处理的K线索引
    index = ContextInfo.barpos
    
    # 获取历史行情数据
    # 使用 get_market_data_ex 获取数据,返回字典 {code: dataframe}
    # 字段需要 'close' (收盘价) 和 'volume' (成交量)
    market_data = ContextInfo.get_market_data_ex(
        ['close', 'volume'], 
        [ContextInfo.stock_code], 
        period=period, 
        count=ContextInfo.data_count, 
        dividend_type='front', # 前复权
        subscribe=True
    )
    
    if ContextInfo.stock_code not in market_data:
        return
        
    df = market_data[ContextInfo.stock_code]
    
    # 如果数据量不足以计算指标,则返回
    if len(df) < ContextInfo.fi_period + 2:
        return

    # --- 计算强力指数 (Force Index) ---
    
    # 1. 计算价格变化: 今日收盘 - 昨日收盘
    # diff() 函数计算当前行与上一行的差值
    df['price_change'] = df['close'].diff()
    
    # 2. 计算原始 Force Index: 价格变化 * 成交量
    df['raw_fi'] = df['price_change'] * df['volume']
    
    # 3. 计算平滑后的 Force Index (EMA)
    # 使用 pandas 的 ewm 方法计算指数加权移动平均
    df['ema_fi'] = df['raw_fi'].ewm(span=ContextInfo.fi_period, adjust=False).mean()
    
    # 获取最新和上一个周期的指标值
    # iloc[-1] 是当前K线的值,iloc[-2] 是上一根K线的值
    current_fi = df['ema_fi'].iloc[-1]
    prev_fi = df['ema_fi'].iloc[-2]
    
    # 打印调试信息 (可选)
    # print(f"Time: {df.index[-1]}, FI: {current_fi:.2f}, Prev_FI: {prev_fi:.2f}")

    # --- 交易逻辑 ---
    
    # 获取当前持仓
    positions = get_trade_detail_data(ContextInfo.account_id, 'stock', 'position')
    current_holding = 0
    for pos in positions:
        if pos.m_strInstrumentID + '.' + pos.m_strExchangeID == ContextInfo.stock_code:
            current_holding = pos.m_nVolume
            break

    # 信号判断
    # 1. 买入信号: 上一根 FI < 0 且 当前 FI > 0 (上穿0轴)
    if prev_fi < 0 and current_fi > 0:
        # 如果当前没有持仓,则全仓买入
        # order_target_percent 需要在回测模式或实盘中配合 set_account 使用
        # 这里设置为目标仓位 100% (1.0)
        order_target_percent(ContextInfo.stock_code, 1.0, ContextInfo, ContextInfo.account_id)
        print(f"买入信号触发: {ContextInfo.stock_code}, FI上穿0轴")

    # 2. 卖出信号: 上一根 FI > 0 且 当前 FI < 0 (下穿0轴)
    elif prev_fi > 0 and current_fi < 0:
        # 如果有持仓,则清仓
        # 设置目标仓位为 0%
        order_target_percent(ContextInfo.stock_code, 0.0, ContextInfo, ContextInfo.account_id)
        print(f"卖出信号触发: {ContextInfo.stock_code}, FI下穿0轴")

代码关键点解析

  1. 数据获取 (get_market_data_ex):

    • 我们使用了 get_market_data_ex 接口,这是 QMT 推荐的高效数据接口。
    • 我们需要 closevolume 两个字段来计算 FI。
    • dividend_type='front' 确保使用前复权数据,避免分红派息导致的价格跳空影响指标计算。
  2. 指标计算 (Pandas):

    • df['close'].diff(): 快速计算 $C_t - C_{t-1}$。
    • ewm(span=N): Pandas 提供的指数加权移动平均函数,用于平滑原始的强力指数,使其更适合判断趋势。
  3. 交易函数 (order_target_percent):

    • 使用 order_target_percent 可以简化仓位管理逻辑。
    • 1.0 代表调整仓位至总资产的 100%(全仓)。
    • 0.0 代表调整仓位至 0%(清仓)。
    • 注意: 在实盘中,请确保已通过 ContextInfo.set_account 绑定了正确的资金账号。
  4. 编码格式:

    • 文件首行 # -*- coding: gbk -*- 是必须的,以防止中文注释在 QMT 编辑器中出现乱码。

Q&A

Q1: 强力指数的周期参数(N)应该如何选择?
A1: 埃尔德博士建议:

  • N=2: 用于捕捉短期的买卖机会。当趋势向上时,2日 EMA FI 跌破0轴通常是买入时机(回调买入)。
  • N=13: 用于识别中期趋势。如本策略所示,上穿0轴看多,下穿0轴看空。

Q2: 为什么使用 get_market_data_ex 而不是 get_market_data
A2: get_market_data 是旧版接口,官方已不建议使用。get_market_data_ex 返回标准的 Pandas DataFrame 格式,处理数据更加方便且性能更好。

Q3: 这个策略可以直接用于实盘吗?
A3: 代码逻辑是完整的,但实盘前建议:

  1. 在 QMT 回测模块中进行历史回测,验证收益风险比。
  2. 修改 ContextInfo.account_id 为您的真实账号。
  3. 考虑添加风控逻辑(如止损、最大持仓限制等),因为单一指标策略通常存在假突破风险。