mcpField
O
orderly-positions-tpsl

orderly-positions-tpsl

github.com/orderlynetworkその他261 回インストール1 日前に更新
リポジトリ

orderly-positions-tpsl について

orderly-positions-tpslは、Orderly Networkの無期限先物ポジションとリスク設定を管理するスキルです。REST APIとReactフックを使ったポジション・損益データ、レバレッジ、利確・損切り注文を扱います。

主な機能

  1. 01ポジションと履歴の取得
  2. 02ポジション配信と損益の更新
  3. 03全量または一部の決済
  4. 04レバレッジの取得と設定
  5. 05利確・損切り注文の設定とキャンセル
  6. 06証拠金と清算リスクの確認

活用シーン

  1. 01ポジション管理画面の構築
  2. 02含み損益とレバレッジの追跡
  3. 03ポジションの利確・損切り注文の設定や取消
  4. 04証拠金と清算リスクの監視

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/orderlynetwork/skills --skill orderly-positions-tpsl

インストール後、Claude Code で/orderly-positions-tpslを入力して読み込まれたか確認します。

詳細

Orderly Network:ポジションと TP/SL

このスキルでは、ポジション管理、PnL の追跡、レバレッジ設定、リスク管理のためのテイクプロフィット(TP)注文とストップロス(SL)注文の設定について説明します。

使用する場面

  • ポジション管理インターフェースを構築する
  • TP/SL によるリスク管理を実装する
  • 未実現 PnL を追跡する
  • レバレッジ設定を調整する

前提条件

  • Orderly でポジションを保有していること
  • 無期限先物について理解していること
  • read および trading スコープを持つ API キー

ポジションのデータ構造

interface Position {
  symbol: string; // e.g., "PERP_ETH_USDC"
  position_qty: number; // Positive = long, Negative = short
  average_open_price: number; // Entry price
  mark_price: number; // Current mark price
  unrealized_pnl: number; // Unrealized profit/loss
  unrealized_pnl_roi: number; // ROI percentage
  mmr: number; // Maintenance margin ratio
  imr: number; // Initial margin ratio
  notional: number; // Position value
  leverage: number; // Current leverage
  est_liq_price: number; // Estimated liquidation price
  cost_position: number; // Position cost
  settle_price: number; // Settlement price
  unsettled_pnl: number; // Unsettled PnL
}

ポジションの取得(REST API)

// Get all positions
GET /v1/positions

// Get position for specific symbol
GET /v1/position/{symbol}

// Example response
{
  "success": true,
  "data": {
    "rows": [
      {
        "symbol": "PERP_ETH_USDC",
        "position_qty": 0.5,
        "average_open_price": 3000,
        "mark_price": 3100,
        "unrealized_pnl": 50,
        "unrealized_pnl_roi": 0.0333,
        "mmr": 0.01,
        "imr": 0.02,
        "notional": 1550,
        "leverage": 10,
        "est_liq_price": 2700
      }
    ]
  }
}

React SDK:usePositionStream

PnL を自動更新しながら、ポジションをリアルタイムでストリーミングします。

import { usePositionStream } from '@orderly.network/hooks';

function PositionsTable() {
  const {
    rows,
    aggregated,
    totalUnrealizedROI,
    isLoading
  } = usePositionStream();

  if (isLoading) return <div>Loading positions...</div>;

  return (
    <div>
      <div className="summary">
        <h3>Total Unrealized PnL: {aggregated?.totalUnrealizedPnl?.toFixed(2)} USDC</h3>
        <p>ROI: {(totalUnrealizedROI * 100).toFixed(2)}%</p>
      </div>

      <table>
        <thead>
          <tr>
            <th>Symbol</th>
            <th>Size</th>
            <th>Entry Price</th>
            <th>Mark Price</th>
            <th>Unrealized PnL</th>
            <th>Leverage</th>
            <th>Liq. Price</th>
          </tr>
        </thead>
        <tbody>
          {rows.map((position) => (
            <tr key={position.symbol}>
              <td>{position.symbol}</td>
              <td className={position.position_qty > 0 ? 'long' : 'short'}>
                {position.position_qty > 0 ? '+' : ''}{position.position_qty}
              </td>
              <td>{position.average_open_price.toFixed(2)}</td>
              <td>{position.mark_price.toFixed(2)}</td>
              <td className={position.unrealized_pnl >= 0 ? 'profit' : 'loss'}>
                {position.unrealized_pnl.toFixed(2)} USDC
              </td>
              <td>{position.leverage}x</td>
              <td>{position.liq_price.toFixed(2)}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

ポジションを決済する

部分決済
import { usePositionClose } from '@orderly.network/hooks';

function ClosePositionButton({ symbol, positionQty }: { symbol: string; positionQty: number }) {
  const { closePosition, isClosing } = usePositionClose();

  const handleClose = async (percentage: number) => {
    const quantity = Math.abs(positionQty) * (percentage / 100);
    await closePosition({
      symbol,
      qty: quantity,
      side: positionQty > 0 ? 'SELL' : 'BUY',
    });
  };

  return (
    <div>
      <button onClick={() => handleClose(25)} disabled={isClosing}>Close 25%</button>
      <button onClick={() => handleClose(50)} disabled={isClosing}>Close 50%</button>
      <button onClick={() => handleClose(100)} disabled={isClosing}>Close 100%</button>
    </div>
  );
}
成行決済(REST API)
// Close entire position at market price
POST /v1/order
Body: {
  symbol: 'PERP_ETH_USDC',
  side: positionQty > 0 ? 'SELL' : 'BUY',
  order_type: 'MARKET',
  order_quantity: Math.abs(positionQty).toString(),
  reduce_only: true,
}

レバレッジ管理

現在のレバレッジを取得する
GET /v1/client/leverage?symbol={symbol}

// Response
{
  "success": true,
  "data": {
    "leverage": 10,
    "max_leverage": 25
  }
}
レバレッジを設定する
POST /v1/client/leverage
Body: {
  symbol: 'PERP_ETH_USDC',
  leverage: 15,  // New leverage value
}

// React SDK
import { useLeverage } from '@orderly.network/hooks';

function LeverageSlider({ symbol }: { symbol: string }) {
  const { leverage, maxLeverage, setLeverage, isLoading } = useLeverage(symbol);

  const handleChange = async (newLeverage: number) => {
    try {
      await setLeverage(newLeverage);
    } catch (error) {
      console.error('Failed to set leverage:', error);
    }
  };

  return (
    <div>
      <label>Leverage: {leverage}x</label>
      <input
        type="range"
        min="1"
        max={maxLeverage}
        value={leverage}
        onChange={(e) => handleChange(parseInt(e.target.value))}
        disabled={isLoading}
      />
    </div>
  );
}

テイクプロフィット/ストップロス注文

TP/SL 注文の種類
種類説明
TAKE_PROFIT価格が目標値(利益)に達したときに発動する
STOP_LOSS価格がしきい値を下回ったときに発動する
TRAILING_STOP価格に追従する動的なストップ注文
useTPSLOrder フックを使用する
import { useTPSLOrder } from '@orderly.network/hooks';

function TPSSettings({ position }: { position: Position }) {
  const [computed, { setValue, submit, validate, reset }] = useTPSLOrder(position);

  const handleSubmit = async () => {
    try {
      await validate();
      await submit();
      console.log('TP/SL order placed');
    } catch (error) {
      console.error('TP/SL failed:', error);
    }
  };

  return (
    <div className="tpsl-form">
      <h4>Take Profit</h4>
      <div>
        <label>Trigger Price</label>
        <input
          type="number"
          placeholder="TP Price"
          onChange={(e) => setValue('tp_trigger_price', e.target.value)}
        />
      </div>
      <div>
        <label>Or Offset %</label>
        <input
          type="number"
          placeholder="e.g., 5 for 5%"
          onChange={(e) => setValue('tp_offset_percentage', parseFloat(e.target.value))}
        />
      </div>

      <h4>Stop Loss</h4>
      <div>
        <label>Trigger Price</label>
        <input
          type="number"
          placeholder="SL Price"
          onChange={(e) => setValue('sl_trigger_price', e.target.value)}
        />
      </div>
      <div>
        <label>Or Offset %</label>
        <input
          type="number"
          placeholder="e.g., -5 for -5%"
          onChange={(e) => setValue('sl_offset_percentage', parseFloat(e.target.value))}
        />
      </div>

      <button onClick={handleSubmit}>Set TP/SL</button>
    </div>
  );
}
REST API:TP/SL 用 Algo 注文
// Place TP/SL order (creates both TP and SL as child orders)
POST /v1/algo/order
Body: {
  symbol: 'PERP_ETH_USDC',
  algo_type: 'TP_SL',
  quantity: 5.5,
  trigger_price_type: 'MARK_PRICE',
  child_orders: [
    {
      symbol: 'PERP_ETH_USDC',
      algo_type: 'TAKE_PROFIT',
      side: 'SELL',
      type: 'MARKET',
      trigger_price: 3500,
      reduce_only: true
    },
    {
      symbol: 'PERP_ETH_USDC',
      algo_type: 'STOP_LOSS',
      side: 'SELL',
      type: 'MARKET',
      trigger_price: 2800,
      reduce_only: true
    }
  ]
}

// Positional TP/SL (attached to entire position)
POST /v1/algo/order
Body: {
  symbol: 'PERP_ETH_USDC',
  algo_type: 'POSITIONAL_TP_SL',
  trigger_price_type: 'MARK_PRICE',
  child_orders: [
    {
      symbol: 'PERP_ETH_USDC',
      algo_type: 'TAKE_PROFIT',
      side: 'SELL',
      type: 'CLOSE_POSITION',
      trigger_price: 3500,
      reduce_only: true
    },
    {
      symbol: 'PERP_ETH_USDC',
      algo_type: 'STOP_LOSS',
      side: 'SELL',
      type: 'CLOSE_POSITION',
      trigger_price: 2800,
      reduce_only: true
    }
  ]
}
STOP 注文(ストップ成行)
POST /v1/algo/order
Body: {
  symbol: 'PERP_ETH_USDC',
  algo_type: 'STOP',
  quantity: 5.5,
  side: 'BUY',
  type: 'LIMIT',
  trigger_price_type: 'MARK_PRICE',
  trigger_price: 4.203,
  price: 3.5  // Limit price for the triggered order
}
TP/SL 注文をキャンセルする
// Cancel single algo order
DELETE /v1/algo/order?order_id={order_id}&symbol={symbol}

// Cancel all algo orders for symbol
DELETE /v1/algo/orders?symbol={symbol}

// React SDK
const [algoOrders, { cancelAlgoOrder }] = useAlgoOrderStream();
await cancelAlgoOrder(orderId);

ポジション履歴

GET /v1/position_history?symbol={symbol}&start={timestamp}&end={timestamp}

// Response includes closed positions with realized PnL

PnL の計算

未実現 PnL
// For LONG positions
unrealizedPnL = (markPrice - averageOpenPrice) * positionQty;

// For SHORT positions
unrealizedPnL = (averageOpenPrice - markPrice) * Math.abs(positionQty);
ROI
// Return on Investment
roi = unrealizedPnL / ((averageOpenPrice * Math.abs(positionQty)) / leverage);
清算価格
// For LONG positions
liqPrice = averageOpenPrice * (1 - mmr - 1 / leverage);

// For SHORT positions
liqPrice = averageOpenPrice * (1 + mmr + 1 / leverage);

リスク指標

// Available fields from GET /v1/positions response:
{
  "current_margin_ratio_with_orders": 1.2385,
  "free_collateral": 450315.09,
  "initial_margin_ratio": 0.1,
  "initial_margin_ratio_with_orders": 0.1,
  "maintenance_margin_ratio": 0.05,
  "maintenance_margin_ratio_with_orders": 0.05,
  "margin_ratio": 1.2385,
  "open_margin_ratio": 1.2102,
  "total_collateral_value": 489865.71,
  "total_pnl_24_h": 0
}

マージンと担保:階層の仕組み

Orderly は多層のリスクシステムを採用しています。それぞれの要素の関係は次のとおりです。

Your Deposit
     ↓
[Collateral Factor] → Determines effective collateral value
     ↓
Effective Collateral (what you can actually use)
     ↓
[IMR/MMR] → Required margin per position
     ↓
Used Collateral (locked in positions)
     ↓
Free Collateral (available for new trades)
3 つの階層の説明

1. 担保係数(トークンレベル)

  • Orderly のリスクチームがトークンごとに設定します
  • 例:USDC = 1.0、USDT = 0.95
  • 入金時に適用されます:$1000 USDT × 0.95 = 実効担保 $950
  • 確認先:GET /v1/public/token

2. IMR/MMR(ポジションレベル)

  • IMR(初期証拠金率):ポジションを建てるのに必要な最小担保額です
  • MMR(維持証拠金率):ポジションを維持するのに必要な最小担保額です
  • レバレッジによって決まります:レバレッジ 10 倍 = IMR 10%、MMR 約 5%
  • ポジションの想定元本に適用されます:$10,000 のポジション × IMR 10% = 必要額 $1,000
  • 確認先:ポジションオブジェクトまたはシンボル情報

3. アカウントマージン比率(アカウントレベル)

  • margin_ratio = total_collateral / total_notional
  • この値が MMR に近づくと、清算が近づいています
  • 確認先:GET /v1/client/holding
計算例
Deposit: $10,000 USDC (collateral_factor = 1.0)
Effective Collateral: $10,000

Open Position: $50,000 ETH-PERP at 10x leverage
IMR Required: $50,000 × 10% = $5,000
MMR Required: $50,000 × 5% = $2,500

After opening:
- Used Collateral: $5,000
- Free Collateral: $5,000
- Margin Ratio: $10,000 / $50,000 = 20%

Liquidation happens when:
- Margin Ratio drops to MMR (5%)
- That means your collateral drops to $2,500
- Or position grows to $200,000 notional

要点:IMR の要件(レバレッジによって決定)を満たすには、十分な実効担保(担保係数適用後)が必要です。margin_ratio は、清算までどの程度余裕があるか(MMR によって決定)を示します。

よくある問題

「Position would exceed max leverage」エラー
  • 新しいレバレッジでは、現在の想定元本が上限を超えています
  • ポジションサイズを縮小するか、担保を追加してください
「Insufficient margin for TP/SL」エラー
  • TP/SL 注文には利用可能なマージンが必要です
  • 一部のポジションを決済するか、担保を追加してください
TP/SL が発動しない
  • trigger_price が有効か確認してください
  • 注文のステータスが NEW であることを確認してください
  • 価格が急変し、トリガー価格を飛び越えている可能性があります
清算リスク
  • margin_ratio を注意深く監視してください
  • 早めにストップロスを設定してください
  • ポジションを長期間保有する場合は、ファンディングレートに注意してください

関連スキル

  • orderly-trading-orders - 注文の発注
  • orderly-websocket-streaming - リアルタイムのポジション更新
  • orderly-sdk-react-hooks - SDK の全リファレンス
  • orderly-api-authentication - リクエストへの署名

コメント