🚀 AI 一键生成 joinquant 策略代码

JoinQuant 财务选股:基于存货周转率(inventory_turnover_rate)的策略

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

问题描述

请写一个筛选高存货周转率股票的策略

解决方案

这是一个基于**高存货周转率(High Inventory Turnover Rate)**的量化选股策略。

策略逻辑说明

  1. 核心因子:存货周转率 (inventory_turnover_rate)。
    • 含义:衡量企业销货能力强弱和存货管理效率高低的指标。通常越高越好,说明存货变现速度快,资金占用水平低。
  2. 选股范围:全A股(剔除ST、停牌、次新股)。
  3. 调仓频率:按月调仓(每月第一个交易日)。
  4. 持仓数量:持有存货周转率最高的 20 只股票。
  5. 权重分配:等权重买入。

策略代码

# -*- coding: utf-8 -*-
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')
    
    # 设定股票交易手续费:买入万三,卖出万三加千一印花税
    set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
    
    # 设定持仓数量
    g.stock_num = 20
    
    # 设定按月运行,每月第一个交易日开盘后运行
    run_monthly(rebalance, 1, time='09:30')

def rebalance(context):
    """
    调仓主函数
    """
    # 1. 获取当前所有股票列表
    all_stocks = list(get_all_securities(['stock']).index)
    
    # 2. 过滤掉 ST、停牌、上市不足60天的次新股
    feasible_stocks = filter_basic_stock(context, all_stocks)
    
    # 3. 查询财务数据,获取存货周转率最高的股票
    # 注意:indicator.inventory_turnover_rate 是存货周转率
    q = query(
        valuation.code,
        indicator.inventory_turnover_rate
    ).filter(
        valuation.code.in_(feasible_stocks)
    ).order_by(
        indicator.inventory_turnover_rate.desc() # 按存货周转率降序排列
    ).limit(
        g.stock_num
    )
    
    df = get_fundamentals(q)
    
    if df is None or len(df) == 0:
        log.warn("未选出符合条件的股票,本月不调仓")
        return
        
    target_list = list(df['code'])
    log.info("本月目标持仓: %s" % target_list)
    
    # 4. 执行调仓操作
    adjust_position(context, target_list)

def adjust_position(context, target_list):
    """
    执行具体的买卖操作
    """
    # 获取当前持仓
    current_holdings = list(context.portfolio.positions.keys())
    
    # 卖出不在目标列表中的股票
    for stock in current_holdings:
        if stock not in target_list:
            order_target_value(stock, 0)
    
    # 买入目标列表中的股票
    # 等权重分配资金
    position_count = len(target_list)
    if position_count > 0:
        # 将总资产平分
        value_per_stock = context.portfolio.total_value / position_count
        
        for stock in target_list:
            order_target_value(stock, value_per_stock)

def filter_basic_stock(context, stock_list):
    """
    基础过滤器:剔除ST、停牌、次新股
    """
    current_data = get_current_data()
    return [stock for stock in stock_list 
            if not current_data[stock].is_st 
            and not current_data[stock].paused 
            and 'ST' not in current_data[stock].name 
            and '*' not in current_data[stock].name 
            and '退' not in current_data[stock].name 
            and (context.current_dt.date() - get_security_info(stock).start_date).days > 60]

常见问题 (Q&A)

Q: 为什么要使用 get_fundamentals 查询 indicator.inventory_turnover_rate
A: get_fundamentals 是聚宽提供的财务数据查询接口,indicator 表包含了经过计算的财务指标。inventory_turnover_rate 直接提供了存货周转率数据,避免了手动使用营业成本除以平均存货的计算过程,且该接口会自动匹配当前时间点能获取到的最新财报数据,避免未来函数。

Q: 策略中的 run_monthly 是什么意思?
A: 这是一个定时运行函数。run_monthly(rebalance, 1, time='09:30') 表示在每个月的第 1 个交易日的 09:30 执行 rebalance 函数。财务数据通常按季度更新,按月调仓可以及时捕捉财报发布后的指标变化,同时避免过度频繁交易产生的高额手续费。

Q: 如何优化这个策略?
A: 单一的存货周转率因子可能存在行业偏差(例如零售业通常比制造业周转快)。优化方向包括:

  1. 行业中性化:在每个行业内分别选取高周转率的股票,而不是在全市场混排。
  2. 结合其他因子:例如结合 毛利率 (Gross Margin),防止选中虽然周转快但利润极薄甚至亏损甩货的公司;或者结合 ROE 寻找高质量公司。
  3. 去极值:剔除数据异常的股票。