Added

v1.11.0 - 2025-10-21

Added

  • New instruments WebSocket channel for real-time instrument list updates

    • Purpose: Receive immediate notifications when trading instruments are added or expire, keeping your application synchronized with available markets
    • Benefits: Eliminates need for polling /instruments endpoint, instant awareness of new trading opportunities, automatic cleanup of expired instruments
    • New capabilities: Subscribe to specific markets (BTC, ETH, ARB) or all markets, receive initial snapshot on subscription, get update timestamp with each event

    Example subscription (single market):

    {
      "type": "subscribe",
      "subscriptions": [
        {
          "channel": "instruments",
          "query": {
            "market": "BTC"
          }
        }
      ]
    }

    Example subscription (all markets):

    {
      "type": "subscribe",
      "subscriptions": [
        {
          "channel": "instruments",
          "query": {}
        }
      ]
    }

    Event data received:

    {
      "kind": "event",
      "type": "instruments",
      "timestamp_ms": 1677721600000,
      "data": {
        "updated_at": 1677721600000,
        "instruments": [
          "BTC_USDC-PERPETUAL",
          "BTC_USDC-31OCT25-130000-C",
          "BTC_USDC-31OCT25-130000-P",
          "BTC_USDC-31OCT25-135000-C",
          "BTC_USDC-31OCT25-135000-P"
        ]
      },
      "subscription": {
        "channel": "instruments",
        "query": {
          "market": "BTC"
        }
      }
    }

    Data fields:

    • updated_at: Unix timestamp in milliseconds
    • instruments: Array of instrument names currently available for trading

    Query parameters:

    • market (optional): Base token (BTC, ETH, or ARB). If omitted, subscribes to all markets

    Use cases:

    • Trading applications dynamically updating available instruments
    • Automated trading systems detecting new option expirations
    • Market monitoring tools tracking instrument lifecycle
    • Risk management systems responding to expired instruments

Changed

  • Breaking Change: Endpoint GET /instruments now returns object with timestamp instead of array

    Before:

    // Old response format
    const response = await fetch('/instruments?market=BTC');
    const instruments: string[] = await response.json();
    // Returns: ["BTC_USDC-PERPETUAL", "BTC_USDC-31OCT25-130000-C", ...]

    After:

    // New response format
    const response = await fetch('/instruments?market=BTC');
    const data: {
      updated_at: number;  // Unix timestamp in milliseconds
      instruments: string[];
    } = await response.json();
    // Returns: {
    //   updated_at: 1677721600000,
    //   instruments: ["BTC_USDC-PERPETUAL", "BTC_USDC-31OCT25-130000-C", ...]
    // }
    
    // Access instruments array
    const instruments = data.instruments;
    // Use timestamp for caching/change detection
    const lastUpdate = new Date(data.updated_at);  // Convert to Date object

    Benefits:

    • Cache optimization: Use updated_at timestamp (milliseconds) to implement efficient caching strategies
    • Change detection: Compare timestamps to determine if instrument list has changed
    • Synchronization: Coordinate REST API data with WebSocket instruments channel updates using the same timestamp
    • Better performance: Avoid unnecessary processing when instrument list hasn't changed

    Migration:

    1. Update response type to expect object instead of array
    2. Access instruments via data.instruments property
    3. Optionally implement caching using data.updated_at timestamp
    4. Consider migrating to WebSocket instruments channel for real-time updates
  • Breaking Change: Endpoint POST /limit response format simplified - matched field removed

    Before:

    // Old response format
    const response = await fetch('/limit', {
      method: 'POST',
      body: JSON.stringify([/* orders */])
    });
    const result: {
      posted: Array<Order>;
      matched: Array<Order>;  // Separate array for matched orders
      rejected: Array<Order>;
    } = await response.json();

    After:

    // New response format
    const response = await fetch('/limit', {
      method: 'POST',
      body: JSON.stringify([/* orders */])
    });
    const result: {
      posted: Array<Order>;   // Now includes both posted AND matched orders
      rejected: Array<Order>;
    } = await response.json();
    // Note: matched field no longer exists - matched orders are merged into 'posted' array

    Benefits:

    • Simplified response structure: Easier to process all successful orders in one array
    • Reduced complexity: No need to merge posted and matched arrays client-side
    • Clearer semantics: All successfully processed orders (whether posted to orderbook or immediately matched) are in posted

    Migration:

    1. Update response type to remove matched field
    2. Process all successful orders from the posted array (includes both posted and matched orders)
    3. If you need to distinguish matched orders, check the order_state field (will be filled or open)
    4. Remove any client-side code that separately processed the matched array

Documentation

  • Complete REST API documentation updates

    • Updated /instruments endpoint OpenAPI schema with new InstrumentsData response type
    • Added detailed field descriptions for updated_at and instruments properties
    • Updated endpoint description to highlight new timestamp functionality
  • Complete WebSocket API documentation updates

    • Added detailed channel description for instruments channel
    • Added event data structures with field descriptions
    • Added subscription examples for both single market and all markets scenarios
    • Updated Available Channels table with new instruments entry
    • Updated Event Types table with instruments event
    • Added comprehensive use cases and implementation notes