3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在构建多因子策略、多策略组合或分仓操作时,量化交易者经常会遇到一个经典问题:同一只标的(例如某只热门ETF)同时被多个子策略选中,并分配了不同的权重。
如果每个子策略独立运行并直接调用 order 或 order_value 下单,会导致以下痛点:
本文将为您提供在聚宽(JoinQuant)平台中进行多仓位管理、合并同一标的权重并避免重复下单的完整解决方案。
在聚宽中,避免重复下单的最佳实践是**“集中决策,统一调仓”**。具体步骤如下:
set_subportfolios 划分不同的策略账户(如股票仓位、期货仓位等)。context.portfolio.total_value)计算出该标的合并后的目标绝对价值。order_target_value 一步到位调整到目标仓位。聚宽引擎会自动计算当前持仓与目标持仓的差额,仅对差额部分进行单笔下单,从而彻底避免重复下单。以下是一个完整的聚宽策略示例。我们创建了两个虚拟的子策略,它们分别对一组 ETF 进行打分和权重分配。策略在每月初运行,自动合并相同 ETF 的权重并进行精准调仓。
# 导入聚宽函数库
import pandas as pd
from jqdata import *
def initialize(context):
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 设定交易费用:买入万三,卖出万三加千一印花税,最低5元
set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
# 初始化子账户:将资金等分为两个子仓位(例如:策略A仓位和策略B仓位)
init_cash = context.portfolio.starting_cash / 2
set_subportfolios([
SubPortfolioConfig(cash=init_cash, type='stock'), # 子账户 0
SubPortfolioConfig(cash=init_cash, type='stock') # 子账户 1
])
# 定时运行:每月第一个交易日开盘运行调仓
run_monthly(rebalance_portfolio, monthday=1, time='09:30')
def rebalance_portfolio(context):
log.info("--------- 开始多仓位合并调仓 ---------")
# 1. 模拟子策略 A 选中的 ETF 及其目标权重
strategy_a_weights = {
'510300.XSHG': 0.4, # 沪深300 ETF
'510500.XSHG': 0.3, # 中证500 ETF
'159915.XSHE': 0.3 # 创业板 ETF
}
# 2. 模拟子策略 B 选中的 ETF 及其目标权重
strategy_b_weights = {
'510300.XSHG': 0.5, # 沪深300 ETF (与策略A重合)
'510050.XSHG': 0.3, # 上证50 ETF
'159915.XSHE': 0.2 # 创业板 ETF (与策略A重合)
}
# 3. 合并全局权重
# 我们需要将两个子账户的权重映射到总账户资产中。由于资金各占50%,全局权重 = (策略A权重 * 0.5) + (策略B权重 * 0.5)
global_weights = {}
for stock, weight in strategy_a_weights.items():
global_weights[stock] = global_weights.get(stock, 0.0) + weight * 0.5
for stock, weight in strategy_b_weights.items():
global_weights[stock] = global_weights.get(stock, 0.0) + weight * 0.5
log.info("合并后的全局目标权重: %s" % str(global_weights))
# 4. 获取当前总资产
total_value = context.portfolio.total_value
# 5. 获取当前持仓中,不在目标全局权重列表中的标的,并将其清仓
current_positions = list(context.portfolio.positions.keys())
for stock in current_positions:
if stock not in global_weights:
log.info("标的 %s 不在目标组合中,执行清仓。" % stock)
order_target(stock, 0)
# 6. 按照合并后的目标价值进行精准调仓(避免重复下单)
# 默认在 subportfolios[0](主仓位)中统一管理合并后的现货头寸
for stock, weight in global_weights.items():
target_value = total_value * weight
log.info("标的 %s 合并后目标价值为: %.2f 元" % (stock, target_value))
# 使用目标价值下单,聚宽会自动计算差额并单笔补单/减仓
order_target_value(stock, target_value, pindex=0)
log.info("--------- 调仓完成 ---------")
order_target_value(security, value, pindex=0):
这是避免重复下单的灵魂函数。假设你当前持有 510300.XSHG 价值 10 万元,合并权重后计算出的目标价值为 15 万元。调用此函数后,系统不会先卖出 10 万再买入 15 万,也不会直接买入 15 万,而是自动计算差额(15万 - 10万 = 5万),仅下一笔 5 万元的买单。这极大地节省了滑点和佣金。
context.portfolio.total_value:
获取当前账户的动态总权益(包含现金和所有子仓位的持仓市值)。以此为基准计算绝对价值,能确保组合整体杠杆率和权重分配的精确性。
set_subportfolios:
通过划分不同的子账户,您可以清晰地在后台监控不同策略的资金曲线,但在实际下单执行阶段,通过全局合并逻辑在主仓位(pindex=0)中统一调仓,完美兼顾了“策略独立统计”与“交易集中执行”的需求。