🚀 AI 一键生成 joinquant 策略代码
立即体验

joinquant 平台如何使用 MinScore 进行反向因子打分组合优化?(附 Python 源码)

joinquant | 发布时间: 2026/7/29
以下内容由 EasyQuant 生成。

问题描述

请根据以下 SEO 主题生成完整页面内容:

Title: joinquant 组合优化器:MinScore 反向打分模型应用指南

Question: 在 joinquant 中如何使用 MinScore 目标函数根据反向因子打分进行组合优化?

解决方案

JoinQuant 组合优化器:MinScore 反向打分模型应用指南

在量化投资中,某些因子的数值越小往往代表标的的潜在表现越好(例如低估值因子 PE/PB、低波动率因子或风险指标)。在 JoinQuant(聚宽) 平台上,为了给这类“打分越小越优”的标的赋予更高权重,我们可以使用投资组合优化器(portfolio_optimizer)中的 MinScore 目标函数。


一、什么是 MinScore 目标函数?

MinScore 是 JoinQuant 投资组合优化模块提供的一种优化目标:

  • 核心逻辑:在满足给定的约束条件(如资产权重上下限、风险暴露限制、行业集中度等)的前提下,优先给予打分较低的标的更高的投资权重。
  • 适用场景:适用于反向因子或风险指标打分选股,例如按照市盈率(PE)从低到高排序打分、对估值/波动率指标进行打分构建组合等。

二、MinScore API 语法与参数说明

在聚宽策略中,使用 MinScore 需要引入优化器库:

from jqlib.optimizer import portfolio_optimizer, MinScore, Bound, WeightConstraint

目标函数声明

target = MinScore(scores)
  • scores (pandas.Series): 必填参数,Index 为股票代码(如 '000001.XSHE'),Value 为对应的数值或打分。

三、完整策略代码示例

以下示例展示了如何在聚宽平台利用 MinScore 目标函数,对选定股票池根据反向指标(如低 PE 因子)进行组合权重优化:

import pandas as pd
from jqdata import *
from jqlib.optimizer import portfolio_optimizer, MinScore, Bound, WeightConstraint

def initialize(context):
    # 设定基准与交易参数
    set_benchmark('000300.XSHG')
    set_option('use_real_price', True)
    
    # 设置股票手续费
    set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
    
    # 按月定时调仓
    run_monthly(rebalance, monthday=1, time='09:30', reference_security='000300.XSHG')

def rebalance(context):
    # 1. 获取沪深300成分股作为选股池
    stocks = get_index_stocks('000300.XSHG')[:30] # 示例取前30只
    
    # 2. 查询财务数据(如市盈率 PE)作为打分依据
    q = query(valuation.code, valuation.pe_ratio).filter(valuation.code.in_(stocks))
    df_pe = get_fundamentals(q, date=context.previous_date)
    
    if df_pe.empty:
        return
        
    # 构建打分 Series(PE越低,Score越小)
    scores = pd.Series(df_pe['pe_ratio'].values, index=df_pe['code'].values).dropna()
    valid_stocks = list(scores.index)
    
    # 3. 使用 MinScore 进行组合优化
    # 目标:打分(PE)越低权重越高;约束:组合总权重在90%-100%,单股持仓不超过15%
    optimized_weight = portfolio_optimizer(
        date=context.previous_date,
        securities=valid_stocks,
        target=MinScore(scores=scores),
        constraints=[WeightConstraint(low=0.9, high=1.0)],
        bounds=[Bound(low=0.0, high=0.15)],
        return_none_if_fail=True
    )
    
    # 4. 执行调仓
    if optimized_weight is not None:
        log.info("优化权重成功:", optimized_weight)
        # 卖出不在优化结果中的持仓
        for stock in context.portfolio.positions.keys():
            if stock not in optimized_weight or optimized_weight[stock] == 0:
                order_target_value(stock, 0)
        # 按优化比例下单
        total_value = context.portfolio.total_value
        for stock, weight in optimized_weight.items():
            order_target_value(stock, total_value * weight)
    else:
        log.warn("组合优化失败,保持现有持仓")

四、注意事项与最佳实践

  1. 数据清洗与缺失值处理:传入 MinScorescores 中不能包含 NaNInf,需提前过滤或填充缺失值。
  2. 配合约束条件使用:单依靠 MinScore 可能会将大部分权重集中在打分最低的一两只股票上,因此必须配合 bounds=[Bound(low, high)] 限制单标的最高持仓比例,并设置行业或市场暴露约束,以分散风险。
  3. 与 MaxScore 的区别:若打分逻辑是“越大越好”(如 ROE、动量因子),请选用 MaxScore;若是“越小越好”(如 PE、PB、波动率),请选用 MinScore