🚀 AI 一键生成 joinquant 策略代码

JoinQuant 期货策略如何监控保证金比例防止强平?

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

问题描述

期货策略里怎么判断当前保证金比例是否过低?我想在被强平前自动减仓

解决方案

在聚宽(JoinQuant)的期货策略中,判断保证金比例是否过低(即风险度过高)通常有两种方法:

  1. 手动计算风险度(推荐):通过 当前持仓保证金 / 账户总资产 计算风险度。一般当该比例超过 80% 或 90% 时,就需要减仓。
  2. 使用内置函数:使用 is_dangerous 函数判断可用资金是否低于设定比例。

下面我将提供一个完整的策略示例,展示如何实时监控风险度,并在风险过高时自动按比例减仓以防止强平。

核心逻辑说明

  1. 获取账户信息:通过 context.portfolio 获取总资产 (total_value) 和当前占用保证金 (margin)。
  2. 计算风险度risk_ratio = margin / total_value
  3. 风控触发:如果 risk_ratio 超过设定的阈值(例如 80%),则触发减仓逻辑。
  4. 执行减仓:遍历当前的多单和空单持仓,按比例(例如平掉 50% 的仓位)或全部平仓来释放保证金。

策略代码实现

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

def initialize(context):
    # 1. 设定期货账户
    # 获取初始资金
    init_cash = context.portfolio.starting_cash
    # 设定账户类型为期货
    set_subportfolios([SubPortfolioConfig(cash=init_cash, type='futures')])
    
    # 2. 设定交易费率和滑点 (以螺纹钢为例,实际需按品种调整)
    set_order_cost(OrderCost(open_commission=0.0001, close_commission=0.0001, close_today_commission=0.0001), type='futures')
    set_slippage(FixedSlippage(0))
    
    # 3. 设定基准
    set_benchmark('RB9999.XSGE')
    
    # 4. 定义全局变量
    g.future_code = 'RB9999.XSGE' # 示例操作标的
    
    # 5. 设定风控阈值
    g.risk_limit = 0.8  # 风险度阈值 (保证金占比超过80%视为危险)
    g.reduce_ratio = 0.5 # 触发风控时,减仓比例 (平掉50%持仓)

    # 6. 运行频率
    run_daily(market_open, time='every_bar')
    # 单独注册一个风控检查函数,确保每分钟或定时检查
    run_daily(check_risk_management, time='every_bar')

def market_open(context):
    # 这里写你的开仓逻辑,仅作演示
    # 示例:随机开仓以增加保证金占用
    if context.portfolio.margin / context.portfolio.total_value < 0.5:
        # 如果风险度低,尝试开多单
        order(g.future_code, 1, side='long')

def check_risk_management(context):
    """
    风控函数:检查保证金比例,过高则强平部分仓位
    """
    # 获取当前账户对象 (如果是多账户,需指定 subportfolios[i])
    portfolio = context.portfolio
    
    # 1. 获取资金数据
    total_value = portfolio.total_value # 总资产
    margin_used = portfolio.margin      # 已用保证金
    
    # 防止除以0错误
    if total_value == 0:
        return

    # 2. 计算当前风险度 (保证金占用比例)
    current_risk = margin_used / total_value
    
    # 打印当前风险日志
    # log.info("当前风险度: {:.2%}".format(current_risk))
    
    # 3. 判断是否超过阈值
    if current_risk >= g.risk_limit:
        log.warn("【风控触发】当前风险度 {:.2%} 超过阈值 {:.2%},开始执行减仓...".format(current_risk, g.risk_limit))
        
        # 执行减仓操作
        reduce_positions(context)

def reduce_positions(context):
    """
    减仓逻辑:遍历所有持仓,按比例平仓
    """
    portfolio = context.portfolio
    
    # 1. 处理多单 (Long Positions)
    for security, pos in portfolio.long_positions.items():
        if pos.total_amount > 0:
            # 计算需要卖出的数量
            target_amount = int(pos.total_amount * (1 - g.reduce_ratio))
            # 如果计算后数量为0但原持有量>0,强制至少平掉1手,或者直接全平
            if target_amount == pos.total_amount and pos.total_amount > 0:
                target_amount = 0 
            
            log.info("正在平多单: {}, 当前持仓: {}, 目标持仓: {}".format(security, pos.total_amount, target_amount))
            
            # 平多单操作:side='long', amount设为目标持仓量
            order_target(security, target_amount, side='long')
            
    # 2. 处理空单 (Short Positions)
    for security, pos in portfolio.short_positions.items():
        if pos.total_amount > 0:
            # 计算需要卖出的数量
            target_amount = int(pos.total_amount * (1 - g.reduce_ratio))
            
            log.info("正在平空单: {}, 当前持仓: {}, 目标持仓: {}".format(security, pos.total_amount, target_amount))
            
            # 平空单操作:side='short', amount设为目标持仓量
            order_target(security, target_amount, side='short')

关键API解析

  1. context.portfolio.margin:

    • 获取当前账户已占用的保证金总额。这是判断风险的核心数据。
  2. context.portfolio.total_value:

    • 获取当前账户的总权益(可用资金 + 保证金 + 浮动盈亏)。
    • 注意:不要使用 available_cash 来做分母,因为可用资金会随着开仓减少,而总权益才是衡量账户抗风险能力的基准。
  3. order_target(security, amount, side='...'):

    • 在期货交易中,平仓必须指定 side
    • 多单side='long'amount 设置为比当前更小的值(或0)。
    • 空单side='short'amount 设置为比当前更小的值(或0)。

另一种方法:使用 is_dangerous

聚宽提供了一个内置函数 is_dangerous,但它的逻辑是基于“可用资金”或“保证金比例”的判断,不如手动计算直观。如果你想用它,用法如下:

# 检查 subportfolios[0] 的保证金比例是否低于 20% (即风险度是否极高)
# 注意:这里的参数含义可能因语境不同而异,建议使用上面的手动计算法更稳妥
if context.subportfolios[0].is_dangerous(0.2):
    log.warn("账户资金处于危险边缘")
    # 执行平仓...

建议

  • 阈值设置:建议将 g.risk_limit 设置在 0.6 到 0.8 之间。期货波动大,留足 20%-40% 的可用资金作为缓冲是非常必要的。
  • 执行频率:建议在 handle_data 或分钟级的 run_daily 中调用风控函数,确保盘中价格剧烈波动时能及时反应。
  • 优先平亏损单:上面的代码是按比例平掉所有仓位。进阶的做法是计算每个持仓的盈亏,优先平掉亏损最大的仓位来保命。

Q&A

Q1: 为什么计算风险度要用 margin / total_value 而不是 margin / available_cash
A1: total_value 代表你的总权益(本金+盈亏)。风险度是指你用了多少总权益去抗单。available_cash 只是剩余没用的钱,它会随着开仓变成0,无法作为分母来衡量整体风险比例。

Q2: order_target 在平仓时,side 参数应该填什么?
A2: side 参数代表你操作的是哪个方向的持仓

  • 如果你持有多单想平仓,side 必须填 'long',并将数量设为 0 或更少。
  • 如果你持有空单想平仓,side 必须填 'short'
  • 不要混淆:平多单虽然是“卖出”动作,但在 order_target 里是对 long 仓位进行目标调整。

Q3: 模拟盘和实盘的保证金计算有区别吗?
A3: 有区别。模拟盘通常按交易所标准保证金计算,而实盘中期货公司通常会在交易所基础上加收几个点(例如交易所10%,期货公司可能收15%)。在编写策略时,建议将风控阈值设得比理论值更保守一些(更低一些),以覆盖这种差异。