Skip to content

Instrument Name Service

Overview

The Instrument Name Service is responsible for generating and maintaining the list of option instruments that are available to trade. This microservice is a critical component of the trading infrastructure, ensuring that all applications have consistent access to the same set of valid instrument names.

Functionality

  • Dynamically generates instrument names based on current market conditions
  • Calculates appropriate strike prices using volatility and time to expiry
  • Processes multiple maturities in parallel for efficiency
  • Stores generated instrument names in Redis for other services to consume
  • Supports multiple underlying assets (BTC, ETH, ARB) through a single endpoint

Usage

The service provides a single endpoint that handles all supported markets:

POST /instruments

This endpoint is meant to be used in a cron job style invocation done at 8AM UTC daily. It processes all markets defined in SupportedBaseTokens in a single request. The endpoint is for internal use only.

Documentation

For more detailed information about the instrument generation process and how it fits into the broader trading system, see the Instruments Documentation.

For reference, here is Deribit's Policy. Deribit launches daily contracts @ 8AM UTC, and will launch longer duration contracts 1 day prior to expiration (creates extra expirations for 24 hours).

Redis Data Structure

Instrument names are stored in Redis using the following key patterns:

  1. Instruments Set - Redis set containing all instrument names for a market:
instruments:{market}

Example: instruments:BTC

  1. Last Updated Timestamp - When the set was last refreshed:
instruments:{market}:updated_at

Example: instruments:BTC:updated_at

Querying Instrument Names

Validating an Individual Instrument Name

To check if a specific instrument name is valid, use the Redis SISMEMBER command on the set:

SISMEMBER instruments:BTC "BTC_USDC-28MAR25-8000-C"

This returns:

  • 1 if the instrument name is valid
  • 0 if the instrument name is not recognized

This approach provides O(1) constant-time lookups, making it extremely efficient even with thousands of instruments.

Retrieving All Instrument Names

To get the complete list of instrument names for a market:

SMEMBERS instruments:BTC

This returns a list of all instrument names for the specified market.

Checking Last Update Time

To verify when instruments were last regenerated:

GET instruments:BTC:updated_at

This returns a timestamp (Unix milliseconds) that can be used to check the freshness of the data.

Strike Generator

The Strike Generator determines appropriate option strike prices based on market conditions, volatility, and time to expiry. Our implementation follows Deribit's approach to strike generation with different intervals based on moneyness categories.

Strike Generation Approach

The strike generator uses a table-based approach similar to Deribit's strike policy:

  1. Strikes are categorized into three moneyness groups:

  2. ATM (At-The-Money): ~40-60 delta, closest to current price

  3. Outer: ~20-40 delta, further from current price
  4. Wings: <20 delta, furthest from current price

  5. Strike intervals are determined by:

  6. Market (BTC, ETH, ARB)

  7. Time to expiry (≤2 days, ≤2 weeks, or ≤2 months)
  8. Expected price movement (high or low volatility)

  9. The generator dynamically calculates delta boundaries to transition between different interval widths, ensuring appropriate coverage across the entire price range.

Special Formatting for ARB

For ARB instruments, we use a special "d" notation for all strikes:

  • Example: 0.38 is formatted as "0d380" (with 3 decimal places)
  • Example: 1.15 is formatted as "1d150" (with 3 decimal places)

This notation is used for all ARB strikes regardless of their value, with a fixed 3 decimal places for consistency.

Testing

Unit tests can be run with the following command:

yarn nx run instruments:test

Integration tests can be run with the following command:

yarn nx run instruments:it

Interactive Strike Generator Tester

The interactive testing tool allows you to:

  • Test strike generation with manual inputs
  • Visualize the strike distribution and spacing
  • Understand how different parameters affect strike generation

Running the Tester

# Run from root directory
yarn ts-node apps/instruments/src/scripts/interactiveStrikeTester.ts

Using the Interactive Tester

When you run the tester, you'll be presented with a simple menu:

=== Strike Generator Test Menu ===
1. Test with manual inputs
2. Exit

Testing with Manual Inputs

Enter the following parameters:

  1. Market: Choose from BTC, ETH, or ARB
  2. Spot Price: Current price of the underlying asset
  3. Annualized Volatility: Enter as a decimal (e.g., 0.5 for 50%)
  4. Days to Expiry: Number of days until option expiration

The tool will generate strikes and display:

  • The complete list of strikes
  • Each strike's percentage difference from spot price
  • The intervals between adjacent strikes
  • A visual representation of the strike distribution
  • Sample instrument names using the generated strikes

Example Output

=== Testing generateStrikes ===
Market: BTC
Spot Price: 86000
Annualized Volatility: 0.5 (50.0%)
Days to Expiry: 15

Generated Strikes:
[80000, 82000, 84000, 86000, 88000, 90000, 100000]

Total strikes generated: 7

Strike Distances from Spot Price:
80000 (-6.98%)
82000 (-4.65%)
84000 (-2.33%)
86000 (0.00%)
88000 (+2.33%)
90000 (+4.65%)
100000 (+16.28%)

Intervals Between Adjacent Strikes:
80000 to 82000: 2000.0000 (2.50%)
82000 to 84000: 2000.0000 (2.44%)
84000 to 86000: 2000.0000 (2.38%)
86000 to 88000: 2000.0000 (2.33%)
88000 to 90000: 2000.0000 (2.27%)
90000 to 100000: 10000.0000 (11.11%)

Strike Distribution Visualization:
--------------------------------------------------------------------------------
|                                                                        80000
     |                                                                   82000
          |                                                              84000
               S                                                         86000 (SPOT)
                    |                                                    88000
                         |                                               90000
                                                            |            100000
--------------------------------------------------------------------------------

Sample Instrument Names:
Call: BTC_USDC-28JUN24-86000-C
Put: BTC_USDC-28JUN24-86000-P

Understanding Strike Distribution

The strike distribution depends on several factors:

  1. Timeframe Category:

  2. ≤2 days: Closest spacing, fewer wings

  3. ≤2 weeks: Intermediate spacing
  4. ≤2 months: Wider spacing for all strikes

  5. Volatility Impact:

  6. High volatility creates wider strike spacing

  7. Low volatility allows for tighter spacing

  8. Delta Boundaries:

  9. ATM strikes (40-60 delta) have the tightest spacing
  10. Outer strikes (20-40 delta) have intermediate spacing
  11. Wings strikes (<20 delta) have the widest spacing

For example, BTC with 15 days to expiry (in the ≤2 months category) with high volatility will use:

  • ATM interval: 2000
  • Outer interval: 5000
  • Wings interval: 10000

The generateStrikes function automatically determines the appropriate intervals based on these factors.

Implementation Notes

  • The service uses Redis transactions (MULTI/EXEC) to ensure atomic operations when updating instrument sets
  • When new instruments are generated, expired instruments are automatically removed
  • All markets share a single Redis client instance for better resource utilization
  • The service implements fault tolerance by handling errors for individual markets separately
  • If processing fails for one market, the service will continue processing other markets
  • The endpoint returns a 200 status code as long as the overall request processing completes, even if some individual markets fail
  • Detailed success/failure information for each market is logged but not included in the response

This documentation is generated from the service README. For the most up-to-date information, refer to the original README