🚀 AI 一键生成 joinquant 策略代码

JoinQuant 因子库:流动性因子(Liquidity)的定义与应用

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

问题描述

如何计算股票的流动性因子?

解决方案

在聚宽(JoinQuant)平台上,计算股票的流动性因子主要有两种方式:一种是直接获取聚宽因子库中已经计算好的风格因子(Liquidity),另一种是使用基础数据(如换手率、成交量)进行手动计算

以下是详细的说明和代码实现。

1. 聚宽风格因子定义(Liquidity)

根据聚宽风险模型因子列表,标准的**流动性因子(Liquidity)**并非简单的换手率,而是由不同期限的换手率加权组合而成,具体计算公式如下:

$$ \text{Liquidity} = 0.35 \cdot \text{ST_M} + 0.35 \cdot \text{AST_Q} + 0.3 \cdot \text{AST_A} $$

其中:

  • ST_M (share_turnover_monthly): 月换手率(过去21日换手率之和的自然对数)。
  • AST_Q (average_share_turnover_quarterly): 季度平均月换手率(过去3个月平均换手率的自然对数)。
  • AST_A (average_share_turnover_annual): 年度平均月换手率(过去12个月平均换手率的自然对数)。

2. 获取方式

方法一:直接调用因子库(推荐)

使用 jqfactor.get_factor_values 直接获取计算好的 liquidity 因子值。这是最方便、最标准的方法。

方法二:使用财务数据查询换手率

使用 get_fundamentals 查询 valuation.turnover_ratio(换手率),这是最基础的流动性指标。

方法三:手动计算(Amihud非流动性因子等)

利用 get_price 获取成交量和价格,自行编写公式计算(如 Amihud 指标 = |收益率| / 成交金额)。


3. 策略代码示例

以下代码展示了如何在策略中通过方法一(获取风格因子)和方法二(查询换手率)来获取流动性数据,并演示了如何根据流动性因子对股票进行排序。

# -*- coding: utf-8 -*-
from jqdata import *
from jqfactor import get_factor_values

def initialize(context):
    # 设定沪深300作为基准
    set_benchmark('000300.XSHG')
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    # 过滤掉order系列API产生的比error级别低的log
    log.set_level('order', 'error')
    
    # 每天开盘前运行
    run_daily(before_market_open, time='09:00')

def before_market_open(context):
    # 设定要查询的股票池,这里以沪深300为例
    stock_list = get_index_stocks('000300.XSHG')
    
    # 获取当前日期
    date = context.previous_date
    
    # --- 方法一:直接获取聚宽风格因子库中的流动性因子 (Liquidity) ---
    # 注意:因子库数据通常在收盘后更新,所以使用 previous_date
    factor_data = get_factor_values(
        securities=stock_list, 
        factors=['liquidity'], 
        end_date=date, 
        count=1
    )
    # 获取流动性因子值 Series (索引为股票代码,值为因子值)
    # liquidity因子值越大,代表流动性越好(基于换手率计算)
    liquidity_series = factor_data['liquidity'].iloc[0]
    
    # 对因子值进行排序(从大到小),取流动性最好的前5只
    top_liquidity_stocks = liquidity_series.sort_values(ascending=False).head(5).index.tolist()
    
    print("【方法一】基于聚宽风格因子(Liquidity)流动性最高的前5只股票:")
    print(top_liquidity_stocks)
    
    # --- 方法二:使用财务数据查询换手率 (Turnover Ratio) ---
    # turnover_ratio: 换手率(%)
    q = query(
        valuation.code,
        valuation.turnover_ratio
    ).filter(
        valuation.code.in_(stock_list)
    ).order_by(
        valuation.turnover_ratio.desc() # 按换手率降序排列
    )
    
    df_fundamentals = get_fundamentals(q, date=date)
    
    # 取换手率最高的前5只
    if not df_fundamentals.empty:
        top_turnover_stocks = df_fundamentals['code'].head(5).tolist()
        print("【方法二】基于换手率(Turnover Ratio)流动性最高的前5只股票:")
        print(top_turnover_stocks)
    
    # --- 方法三:手动计算 Amihud 非流动性因子 (ILLIQ) ---
    # 公式:ILLIQ = mean( |Rt| / (Price_t * Volume_t) )
    # 这里计算过去20天的平均值
    # 注意:Amihud值越大,表示流动性越差(非流动性越高)
    
    # 获取过去20天的价格和成交额数据
    prices = get_price(stock_list, end_date=date, frequency='daily', fields=['close', 'money'], count=21, panel=False)
    
    if not prices.empty:
        # 计算每日收益率的绝对值
        # pct_change计算收益率,abs取绝对值
        # 注意:这里需要处理多只股票的数据,pandas操作需谨慎
        
        # 为了方便计算,我们将数据转换为pivot table
        close_df = prices.pivot(index='time', columns='code', values='close')
        money_df = prices.pivot(index='time', columns='code', values='money')
        
        # 计算收益率
        ret_df = close_df.pct_change().abs()
        
        # 计算每日 ILLIQ = |Ret| / Money
        # 注意:money单位是元,数值很大,结果会很小,通常可以乘以 1e6 或 1e9 方便观察
        daily_illiq = (ret_df / money_df) * 1e9
        
        # 计算过去20天的均值 (去掉第一天因为pct_change产生的NaN)
        avg_illiq = daily_illiq.iloc[1:].mean()
        
        # 排序:Amihud值越小,流动性越好。所以我们按升序排列取前5
        top_amihud_stocks = avg_illiq.sort_values(ascending=True).head(5).index.tolist()
        
        print("【方法三】基于Amihud非流动性因子(ILLIQ)流动性最高的前5只股票:")
        print(top_amihud_stocks)

def handle_data(context, data):
    pass

总结

  1. Liquidity (风格因子):综合了月、季、年维度的换手率,经过了对数处理,是量化模型中常用的标准因子。使用 get_factor_values 获取。
  2. Turnover Ratio (换手率):最直观的流动性指标,反映当天的交易活跃度。使用 get_fundamentals 获取。
  3. Amihud (非流动性因子):衡量单位成交额带来的价格冲击,常用于学术研究和特定策略。需要通过 get_price 获取原始行情数据自行计算。

Q&A

Q: 为什么使用 get_factor_values 获取的 liquidity 因子值有正有负?
A: 聚宽提供的风格因子通常经过了标准化(z-score)处理。0 表示市场平均水平,正值表示流动性高于平均水平,负值表示低于平均水平。

Q: valuation.turnover_ratio 的单位是什么?
A: 单位是百分比(%)。例如获取到的值为 1.5,代表换手率为 1.5%。

Q: 如何在回测中避免未来函数?
A: 在 get_fundamentalsget_factor_values 中,查询日期应使用 context.previous_date(前一个交易日)或者在 before_market_open 中查询。如果在盘中(handle_data)查询当日的换手率或因子,可能会用到收盘后才确定的数据(如全天成交量),从而导致未来函数。上述代码示例中使用了 context.previous_date 来确保数据安全。