本文へ移動
レビューを依頼

vault 開発 · keeper の構成 · 5/7

ポジションの管理

ポジションを読む

売買を判断する前に、keeper は今の状態を知る必要があります。以下の例の exchange は、vault_address=vault_address を指定して作った Exchange です。そのため、どの操作も vault のために署名されます。SDK の注文の関数は、vault_address の引数を取りません。まずテストネットで動かしてください。

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


def get_positions(info: Info, vault_address: str) -> dict:
    """Get all open positions for the vault."""
    state = info.user_state(vault_address)
    positions = {}

    for ap in state["assetPositions"]:
        p = ap["position"]
        coin = p["coin"]
        positions[coin] = {
            "size": float(p["szi"]),           # Positive = long, negative = short
            "entry_price": float(p["entryPx"]),
            "mark_price": float(p["positionValue"]) / abs(float(p["szi"])) if float(p["szi"]) != 0 else 0,
            "unrealized_pnl": float(p["unrealizedPnl"]),
            "leverage": float(p.get("leverage", {}).get("value", 1)),
            "liquidation_px": float(p.get("liquidationPx", 0) or 0),
        }

    return positions

ポジションを建てる

def open_position(exchange: Exchange, vault_address: str,
                  coin: str, side: str, size: float,
                  leverage: int = 10) -> dict:
    """Open a new position for the vault."""

    # Set leverage first
    exchange.update_leverage(leverage, coin, is_cross=True)

    # Place market order (an aggressive IOC limit order with 5% default slippage)
    is_buy = side == "long"
    result = exchange.market_open(coin, is_buy, size)

    return result

ポジションを閉じる

def close_position(exchange: Exchange, vault_address: str,
                   coin: str, size: float) -> dict:
    """Close an existing position."""
    # market_close reads the vault's position, picks the closing side,
    # and sends a reduce-only IOC order.
    result = exchange.market_close(coin, sz=abs(size))

    return result

ポジションの大きさを変える

ポジションの一部を閉じたり、買い増し・売り増ししたりすることもあります。

def adjust_position(exchange: Exchange, info: Info,
                    vault_address: str, coin: str,
                    target_size: float) -> dict | None:
    """Adjust position to target size."""
    positions = get_positions(info, vault_address)
    current = positions.get(coin, {}).get("size", 0.0)

    diff = target_size - current

    if abs(diff) < 0.001:  # Already at target (within tolerance)
        return None

    is_buy = diff > 0
    result = exchange.market_open(coin, is_buy, abs(diff))

    return result

損切りの管理

def set_stop_loss(exchange: Exchange, vault_address: str,
                  coin: str, size: float, stop_price: float) -> dict:
    """Set a stop-loss order for an open position."""
    is_buy = size < 0  # Stop for shorts = buy, for longs = sell

    result = exchange.order(
        coin,
        is_buy,
        abs(size),
        stop_price,
        {"trigger": {
            "triggerPx": stop_price,
            "isMarket": True,
            "tpsl": "sl",
        }},
        reduce_only=True,
    )

    return result

ポジション管理の大事な決まり

  1. 自分のポジションを常に知っておく — 書き込む前に読みます
  2. reduce_only を使う — 閉じる注文では、market_close を使うか reduce_only=True を指定します。うっかり反対側のポジションになるのを防げます
  3. 建てる前に証拠金を確かめる — 自分のリスクの上限を超えないようにします
  4. 一部だけの約定に備える — 流動性が薄いと、成行の注文が一部しか約定しないことがあります
  5. すべてを記録する — 注文、約定、エラーはすべてログに残し、原因を調べられるようにします