Skip to content本文へ移動

Vault Development · Production Vault Operations · 7/7

Risk Management for Vaults

The Stakes

When you run a vault, you're trading other people's money. A bug, a bad signal, or uncontrolled risk can lose depositors' funds. Risk management isn't optional — it's the most important part of your keeper.

Risk Framework

Layer 1: Position-Level Risk

# Maximum size for any single position
MAX_POSITION_PCT = 0.20  # 20% of vault equity

# Maximum leverage per position
MAX_LEVERAGE = 5

# Stop-loss for every position
STOP_LOSS_PCT = 0.05  # 5% loss triggers close

def check_position_risk(position_value: float, vault_equity: float) -> bool:
    """Return True if position is within risk limits."""
    return position_value / vault_equity <= MAX_POSITION_PCT

Layer 2: Portfolio-Level Risk

# Maximum total margin usage
MAX_MARGIN_RATIO = 0.60  # Use at most 60% of equity as margin

# Maximum drawdown before emergency shutdown
MAX_DRAWDOWN_PCT = 0.15  # 15% drawdown → close everything

# Maximum number of simultaneous positions
MAX_POSITIONS = 5

def check_portfolio_risk(margin_ratio: float, drawdown: float,
                         num_positions: int) -> bool:
    """Return True if portfolio is within risk limits."""
    if margin_ratio > MAX_MARGIN_RATIO:
        return False
    if drawdown > MAX_DRAWDOWN_PCT:
        return False
    if num_positions > MAX_POSITIONS:
        return False
    return True

Layer 3: System-Level Risk

Emergency Shutdown

Every vault keeper needs a panic button:

import logging

from hyperliquid.exchange import Exchange
from hyperliquid.info import Info


def emergency_shutdown(exchange: Exchange, info: Info, vault_address: str):
    """Close all positions and cancel all orders immediately.

    `exchange` must be created with vault_address=vault_address.
    """

    # Cancel all open orders
    open_orders = info.open_orders(vault_address)
    for order in open_orders:
        try:
            exchange.cancel(order["coin"], order["oid"])
        except Exception as e:
            logging.error(f"Failed to cancel {order['oid']}: {e}")

    # Close all positions
    state = info.user_state(vault_address)
    for ap in state["assetPositions"]:
        p = ap["position"]
        size = float(p["szi"])
        if abs(size) > 0:
            try:
                # Reduce-only IOC order on the closing side
                exchange.market_close(p["coin"], sz=abs(size))
            except Exception as e:
                logging.error(f"Failed to close {p['coin']}: {e}")

    logging.critical("EMERGENCY SHUTDOWN COMPLETE")

Common Failure Modes

Failure Cause Mitigation
Keeper crash Unhandled exception Auto-restart via systemd
Stale orders WS disconnect during order Reconcile on reconnect
Double orders Retry logic bug Track submitted order IDs
Liquidation Ignoring margin ratio Hard margin limits
Wrong direction Signal inversion bug Sanity check all trades
Infinite loop Logic error Maximum iterations per cycle

Testing Risk Management

Test your risk management code more than your strategy code. A bad strategy loses money slowly; broken risk management loses everything at once.

def test_emergency_shutdown():
    """Test that emergency shutdown closes all positions."""
    # Set up mock positions
    # Call emergency_shutdown
    # Assert all positions are closed
    # Assert all orders are cancelled

vault 開発 · 本番での vault 運用 · 7/7

vault のリスク管理

何がかかっているか

vault を運用するとは、他人のお金で売買することです。バグ1つ、誤ったシグナル1つ、抑えの効かないリスク1つで、預けた人の資金を失うことがあります。リスク管理はおまけではありません。keeper で最も大事な部分です。

リスク管理の枠組み

第1層: ポジションごとのリスク

# Maximum size for any single position
MAX_POSITION_PCT = 0.20  # 20% of vault equity

# Maximum leverage per position
MAX_LEVERAGE = 5

# Stop-loss for every position
STOP_LOSS_PCT = 0.05  # 5% loss triggers close

def check_position_risk(position_value: float, vault_equity: float) -> bool:
    """Return True if position is within risk limits."""
    return position_value / vault_equity <= MAX_POSITION_PCT

第2層: ポートフォリオ全体のリスク

# Maximum total margin usage
MAX_MARGIN_RATIO = 0.60  # Use at most 60% of equity as margin

# Maximum drawdown before emergency shutdown
MAX_DRAWDOWN_PCT = 0.15  # 15% drawdown → close everything

# Maximum number of simultaneous positions
MAX_POSITIONS = 5

def check_portfolio_risk(margin_ratio: float, drawdown: float,
                         num_positions: int) -> bool:
    """Return True if portfolio is within risk limits."""
    if margin_ratio > MAX_MARGIN_RATIO:
        return False
    if drawdown > MAX_DRAWDOWN_PCT:
        return False
    if num_positions > MAX_POSITIONS:
        return False
    return True

第3層: システムのリスク

緊急停止

どの vault の keeper にも、非常ボタンが要ります。

import logging

from hyperliquid.exchange import Exchange
from hyperliquid.info import Info


def emergency_shutdown(exchange: Exchange, info: Info, vault_address: str):
    """Close all positions and cancel all orders immediately.

    `exchange` must be created with vault_address=vault_address.
    """

    # Cancel all open orders
    open_orders = info.open_orders(vault_address)
    for order in open_orders:
        try:
            exchange.cancel(order["coin"], order["oid"])
        except Exception as e:
            logging.error(f"Failed to cancel {order['oid']}: {e}")

    # Close all positions
    state = info.user_state(vault_address)
    for ap in state["assetPositions"]:
        p = ap["position"]
        size = float(p["szi"])
        if abs(size) > 0:
            try:
                # Reduce-only IOC order on the closing side
                exchange.market_close(p["coin"], sz=abs(size))
            except Exception as e:
                logging.error(f"Failed to close {p['coin']}: {e}")

    logging.critical("EMERGENCY SHUTDOWN COMPLETE")

よくある失敗

失敗 原因 対策
keeper が落ちる 処理していない例外 systemd で自動で再起動する
古い注文が残る 注文中に WS が切れる 再接続したときに突き合わせる
二重注文 再試行のロジックのバグ 送った注文 ID を記録する
清算 証拠金の比率を見ていない 証拠金に厳格な上限を設ける
逆向きの売買 シグナルが反転するバグ すべての売買を妥当か確かめる
無限ループ ロジックの誤り 1回の処理で回す上限回数を決める

リスク管理をテストする

戦略のコードよりも、リスク管理のコードを多くテストしてください。悪い戦略はゆっくりお金を失います。壊れたリスク管理は、一度にすべてを失います。

def test_emergency_shutdown():
    """Test that emergency shutdown closes all positions."""
    # Set up mock positions
    # Call emergency_shutdown
    # Assert all positions are closed
    # Assert all orders are cancelled