🚀 AI 一键生成 joinquant 策略代码

基于强力指数(Force Index)的量价分析策略实现

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

问题描述

如何利用强力指数 Force Index 构建交易策略?

解决方案

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

强力指数(Force Index,简称 FI)是由亚历山大·埃尔德(Alexander Elder)博士开发的指标。它结合了价格变动成交量来衡量市场移动背后的力量。

策略原理

强力指数的核心逻辑是:

  1. 价格变动表明了多空双方力量的对比。
  2. 成交量表明了这种力量的强度。

计算公式:
$$FI_1 = (Close_{today} - Close_{yesterday}) \times Volume_{today}$$

原始的 FI 波动非常剧烈,通常需要使用指数移动平均(EMA)进行平滑。

经典的 2 日 EMA 强力指数策略(Elder's 2-day EMA Force Index)

这是一个经典的“顺势回调买入”策略:

  1. 趋势判断:使用较长周期的均线(如 22 日 EMA)判断主趋势。
    • 当收盘价 > 22日 EMA,视为上升趋势。
    • 当收盘价 < 22日 EMA,视为下降趋势。
  2. 强力指数:计算 FI 的 2 日 EMA。
  3. 买入信号
    • 趋势向上(收盘价 > 22日 EMA)。
    • FI(2) < 0(表示主力资金在洗盘或短期回调,是买入良机)。
  4. 卖出信号
    • 趋势反转(收盘价 < 22日 EMA)。
    • 或者当 FI(2) 创出新高后回落(止盈,本策略演示简化为趋势反转卖出)。

策略代码实现

以下是在 JoinQuant 平台上实现的完整策略代码。该策略选取单只标的(如平安银行)进行演示,您可以根据需要修改为多只股票。

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

def initialize(context):
    """
    初始化函数,设定基准、手续费、滑点及策略参数
    """
    # 设定沪深300作为基准
    set_benchmark('000300.XSHG')
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    # 过滤掉order系列API产生的比error级别低的log
    log.set_level('order', 'error')
    
    # 设定手续费:股票类每笔交易时的手续费是:买入时佣金万分之三,卖出时佣金万分之三加千分之一印花税, 每笔交易佣金最低扣5块钱
    set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
    
    # 设定要操作的股票,这里以平安银行为例
    g.security = '000001.XSHE'
    
    # 策略参数
    g.trend_ema_span = 22  # 用于判断长期趋势的EMA周期 (如22日)
    g.fi_ema_span = 2      # 强力指数的平滑EMA周期 (通常为2日或13日)
    
    # 每天开盘时运行
    run_daily(market_open, time='09:30')

def market_open(context):
    """
    每日交易逻辑
    """
    security = g.security
    
    # 1. 获取历史数据
    # 我们需要足够的数据来计算EMA,这里取60天以确保EMA计算稳定
    # fields包含收盘价和成交量
    h_data = attribute_history(security, 60, '1d', ['close', 'volume'], skip_paused=True)
    
    # 如果数据不足(例如刚上市),则跳过
    if len(h_data) < g.trend_ema_span + 2:
        return

    # 2. 计算趋势指标 (22日 EMA)
    # 使用pandas的ewm方法计算指数移动平均
    close_prices = h_data['close']
    trend_ema = close_prices.ewm(span=g.trend_ema_span, adjust=False).mean()
    current_trend_ema = trend_ema[-1]
    current_price = close_prices[-1]
    
    # 3. 计算强力指数 (Force Index)
    # FI = (今日收盘 - 昨日收盘) * 今日成交量
    # diff() 计算今日与昨日的差价
    price_diff = close_prices.diff()
    
    # 计算原始 Force Index
    raw_fi = price_diff * h_data['volume']
    
    # 对 Force Index 进行 EMA 平滑 (2日 EMA)
    fi_ema_series = raw_fi.ewm(span=g.fi_ema_span, adjust=False).mean()
    current_fi = fi_ema_series[-1]
    
    # 4. 获取当前账户资金和持仓
    cash = context.portfolio.available_cash
    position = context.portfolio.positions[security].closeable_amount
    
    # 5. 生成交易信号
    
    # 判断趋势:收盘价在22日均线之上为上升趋势
    is_uptrend = current_price > current_trend_ema
    
    # 买入条件:
    # 1. 处于上升趋势 (Price > EMA22)
    # 2. 强力指数小于0 (FI < 0),代表短期回调,是买入机会
    # 3. 当前无持仓 (简化逻辑,避免重复加仓)
    if is_uptrend and current_fi < 0 and position == 0:
        if cash > 0:
            # 全仓买入
            order_value(security, cash)
            log.info("买入信号触发: 价格(%.2f) > 趋势均线(%.2f) 且 FI(%.2f) < 0" % (current_price, current_trend_ema, current_fi))
            
    # 卖出条件:
    # 1. 趋势反转 (Price < EMA22)
    # 2. 当前有持仓
    elif not is_uptrend and position > 0:
        # 清仓
        order_target(security, 0)
        log.info("卖出信号触发: 趋势反转,价格(%.2f) < 趋势均线(%.2f)" % (current_price, current_trend_ema))
        
    # 记录数据以便在回测图中查看
    record(Price=current_price, Trend_EMA=current_trend_ema, FI=current_fi)

代码解析

  1. 数据获取 (attribute_history):

    • 我们需要 close (收盘价) 和 volume (成交量)。
    • 获取 60 天的数据是为了消除 EMA 计算初期的不稳定,确保计算结果准确。
  2. 计算趋势 EMA:

    • 使用 pandas.Series.ewm(span=22, adjust=False).mean() 计算价格的 22 日指数移动平均线。这是用来界定主趋势的“过滤器”。
  3. 计算强力指数 (FI):

    • price_diff = close_prices.diff():计算 $Close_{today} - Close_{yesterday}$。
    • raw_fi = price_diff * h_data['volume']:计算原始强力指数。
    • fi_ema_series = raw_fi.ewm(span=2, ...):对原始 FI 进行 2 日平滑处理,得到最终指标。
  4. 交易逻辑:

    • 买入: 只有当价格位于长期均线之上(上升趋势),且 FI 指标跌破 0 轴(表示短期卖压释放,价格回调)时买入。这符合“顺大势,逆小势”的原则。
    • 卖出: 当价格跌破长期均线时,认为趋势结束,进行止损或止盈。

常见问题 (Q&A)

Q1: 为什么强力指数要乘以成交量?
A: 单纯的价格变化可能具有欺骗性。如果价格上涨但成交量很小,说明上涨动力不足(量价背离)。强力指数通过引入成交量,放大了伴随巨量成交的价格变动,过滤了无量波动的噪音。

Q2: 2日 EMA 和 13日 EMA 的 FI 有什么区别?
A:

  • 2日 EMA FI:非常敏感,主要用于寻找上升趋势中的短期回调买点(即本策略使用的逻辑)。
  • 13日 EMA FI:相对平滑,主要用于确认长期趋势的变化。如果 13日 FI 持续大于0,说明多头力量主导;持续小于0,说明空头力量主导。

Q3: 如何优化这个策略?
A:

  1. 止盈优化:目前的策略是趋势反转才卖出。可以优化为当 FI 达到某个极高的正值(表示买盘力量耗尽,情绪过热)时分批止盈。
  2. 多股票轮动:将策略应用到股票池中,选取 FI 最低(回调最深)且趋势向上的前 N 只股票进行轮动。
  3. 结合其他指标:结合 RSI 或 MACD 来过滤假信号。

Q4: 为什么使用 adjust=False 计算 EMA?
A: 在 Pandas 中,adjust=True 会计算递归的加权平均,而 adjust=False 更接近于传统的金融技术指标计算公式 $EMA_{today} = \alpha \times Price + (1-\alpha) \times EMA_{yesterday}$。在量化软件中通常使用 adjust=False 以匹配主流看盘软件的结果。