# `ZenQuant.Options.Deribit`
[🔗](https://github.com/ZenHive/zen_quant/blob/v0.8.1/lib/zen_quant/options/deribit.ex#L1)

Deribit option symbol parsing and chain fetching utilities.

Parses Deribit-format option symbols like "BTC-31JAN26-84000-C" into
structured data for analysis, and provides convenience functions for
fetching enriched option chains.

## Example

    ZenQuant.Options.Deribit.parse_option("BTC-31JAN26-84000-C")
    # => {:ok, %{underlying: "BTC", expiry: ~D[2026-01-31], strike: 84000.0, type: :call}}

    ZenQuant.Options.Deribit.parse_option("ETH-28MAR25-2500-P")
    # => {:ok, %{underlying: "ETH", expiry: ~D[2025-03-28], strike: 2500.0, type: :put}}

## API Functions
| Function | Arity | Description | Param Kinds |
| --- | --- | --- | --- |
| `gamma_walls` | 3 | Fetch option chain and compute gamma exposure walls. | `ccxt: value`, `exchange: value` |
| `chain` | 3 | Fetch a complete enriched option chain from Deribit. | `ccxt: value`, `exchange: value` |
| `dvol` | 3 | Fetch and parse Deribit DVOL volatility index history. | `ccxt: value`, `exchange: value` |
| `parse_dvol` | 1 | Parse raw DVOL volatility index history into structured data. | `history_data: value` |
| `valid_option?` | 1 | Check if a symbol is a valid Deribit option format. | `symbol: value` |
| `underlying` | 1 | Extract underlying asset from a Deribit option symbol. | `symbol: value` |
| `option_type` | 1 | Extract option type (:call or :put) from a Deribit option symbol. | `symbol: value` |
| `expiry` | 1 | Extract expiry date from a Deribit option symbol. | `symbol: value` |
| `strike` | 1 | Extract strike price from a Deribit option symbol. | `symbol: value` |
| `parse_option!` | 1 | Parse a Deribit option symbol, raising on failure. | `symbol: value` |
| `parse_option` | 1 | Parse a Deribit option symbol into structured data. | `symbol: value` |

# `chain_result`

```elixir
@type chain_result() :: %{
  chain: %{required(String.t()) =&gt; map()},
  spot: float(),
  enriched_count: non_neg_integer()
}
```

Chain result with option maps keyed by symbol

# `dvol_entry`

```elixir
@type dvol_entry() :: {DateTime.t(), float()}
```

Parsed DVOL history entry: timestamp and volatility index value

# `dvol_result`

```elixir
@type dvol_result() :: %{current: float(), history: [dvol_entry()]}
```

Parsed DVOL result with current value and full history

# `gamma_walls_result`

```elixir
@type gamma_walls_result() :: %{
  walls: [ZenQuant.Options.GammaWalls.wall_entry()],
  spot: float(),
  chain_size: non_neg_integer(),
  enriched_count: non_neg_integer()
}
```

Gamma walls result with wall entries and metadata

# `parsed_option`

```elixir
@type parsed_option() :: %{
  underlying: String.t(),
  expiry: Date.t(),
  strike: float(),
  type: :call | :put
}
```

Parsed option symbol data

# `chain`

```elixir
@spec chain(module(), map(), keyword()) :: {:ok, chain_result()} | {:error, term()}
```

Fetch a complete enriched option chain from Deribit.

## Parameters

  * `ccxt` - Bourse dispatcher module (the top-level `Bourse` module) (value)
  * `exchange` - Built `%Bourse.Exchange{}` handle from `Bourse.exchange(:deribit)` (value)

## Options

  * `currency` - Currency to fetch (default: `"BTC"`)
  * `enrich` - :none or :greeks (default: `:none`)
  * `enrich_limit` - Max instruments to enrich by OI (default: `50`)
  * `max_concurrency` - Parallelism for enrichment (default: `10`)

## Returns

\{:ok, %\{chain, spot, enriched_count\}\} or \{:error, reason\} (`tuple`)

### Example

```elixir
{:ok,
 %{
   spot: 83500.0,
   chain: %{"BTC-31JAN26-84000-C" => %{open_interest: 1200.0}},
   enriched_count: 25
 }}
```

## Errors

  * `:exchange_error` - Pass-through error from ccxt.fetch_option_chain/2

## Composes With

  * `gamma_walls`

```elixir
# descripex:contract
%{
  opts: %{
    currency: %{default: "BTC", type: :string, description: "Currency to fetch"},
    max_concurrency: %{
      default: 10,
      type: :integer,
      description: "Parallelism for enrichment"
    },
    enrich: %{default: :none, type: :atom, description: ":none or :greeks"},
    enrich_limit: %{
      default: 50,
      type: :integer,
      description: "Max instruments to enrich by OI"
    }
  },
  params: %{
    exchange: %{
      description: "Built `%Bourse.Exchange{}` handle from `Bourse.exchange(:deribit)`",
      kind: :value
    },
    ccxt: %{
      description: "Bourse dispatcher module (the top-level `Bourse` module)",
      kind: :value
    }
  },
  errors: [exchange_error: "Pass-through error from ccxt.fetch_option_chain/2"],
  returns: %{
    type: :tuple,
    description: "{:ok, %{chain, spot, enriched_count}} or {:error, reason}"
  },
  returns_example: {:ok,
   %{
     spot: 83500.0,
     chain: %{"BTC-31JAN26-84000-C" => %{open_interest: 1200.0}},
     enriched_count: 25
   }},
  composes_with: [:gamma_walls]
}
```

# `dvol`

```elixir
@spec dvol(module(), map(), keyword()) :: {:ok, dvol_result()} | {:error, term()}
```

Fetch and parse Deribit DVOL volatility index history.

## Parameters

  * `ccxt` - Bourse dispatcher module (the top-level `Bourse` module) (value)
  * `exchange` - Built `%Bourse.Exchange{}` handle from `Bourse.exchange(:deribit)` (value)

## Options

  * `currency` - Currency to fetch (default: `"BTC"`)

## Returns

\{:ok, %\{current, history\}\} or \{:error, reason\} (`tuple`)

### Example

```elixir
{:ok, %{history: [{~U[2026-02-25 12:00:00Z], 44.8}], current: 45.2}}
```

## Errors

  * `:exchange_error` - Pass-through error from ccxt.fetch_volatility_history/3
  * `:empty_history` - No valid DVOL rows in response
  * `:invalid_input` - DVOL payload shape is invalid

```elixir
# descripex:contract
%{
  opts: %{
    currency: %{default: "BTC", type: :string, description: "Currency to fetch"}
  },
  params: %{
    exchange: %{
      description: "Built `%Bourse.Exchange{}` handle from `Bourse.exchange(:deribit)`",
      kind: :value
    },
    ccxt: %{
      description: "Bourse dispatcher module (the top-level `Bourse` module)",
      kind: :value
    }
  },
  errors: [
    exchange_error: "Pass-through error from ccxt.fetch_volatility_history/3",
    empty_history: "No valid DVOL rows in response",
    invalid_input: "DVOL payload shape is invalid"
  ],
  returns: %{
    type: :tuple,
    description: "{:ok, %{current, history}} or {:error, reason}"
  },
  returns_example: {:ok,
   %{history: [{~U[2026-02-25 12:00:00Z], 44.8}], current: 45.2}}
}
```

# `expiry`

```elixir
@spec expiry(String.t()) :: {:ok, Date.t()} | {:error, :invalid_format}
```

Extract expiry date from a Deribit option symbol.

## Parameters

  * `symbol` - Deribit option symbol (value)

## Returns

\{:ok, Date.t()\} or \{:error, :invalid_format\} (`tuple`)

### Example

```elixir
{:ok, ~D[2026-01-31]}
```

## Errors

  * `:invalid_format`

```elixir
# descripex:contract
%{
  params: %{symbol: %{description: "Deribit option symbol", kind: :value}},
  errors: [:invalid_format],
  returns: %{
    type: :tuple,
    description: "{:ok, Date.t()} or {:error, :invalid_format}"
  },
  returns_example: {:ok, ~D[2026-01-31]}
}
```

# `gamma_walls`

```elixir
@spec gamma_walls(module(), map(), keyword()) ::
  {:ok, gamma_walls_result()} | {:error, term()}
```

Fetch option chain and compute gamma exposure walls.

## Parameters

  * `ccxt` - Bourse dispatcher module (the top-level `Bourse` module) (value)
  * `exchange` - Built `%Bourse.Exchange{}` handle from `Bourse.exchange(:deribit)` (value)

## Options

  * `currency` - Currency to fetch (default: `"BTC"`)
  * `enrich_limit` - Max instruments to enrich (default: `50`)
  * `max_concurrency` - Parallelism (default: `10`)
  * `side` - :dealer or :customer sign convention (default: `:dealer`)
  * `min_oi` - Minimum OI to include (default: `0`)
  * `top_n` - Return only top N walls

## Returns

\{:ok, %\{walls, spot, chain_size, enriched_count\}\} or \{:error, reason\} (`tuple`)

### Example

```elixir
{:ok,
 %{
   spot: 83500.0,
   enriched_count: 50,
   walls: [%{type: :support, strike: 84000.0, gex: 1250.0}],
   chain_size: 120
 }}
```

## Errors

  * `:no_spot_price` - Spot extracted from chain is <= 0
  * `:exchange_error` - Pass-through error from chain/2 or exchange module

```elixir
# descripex:contract
%{
  opts: %{
    currency: %{default: "BTC", type: :string, description: "Currency to fetch"},
    max_concurrency: %{default: 10, type: :integer, description: "Parallelism"},
    side: %{
      default: :dealer,
      type: :atom,
      description: ":dealer or :customer sign convention"
    },
    min_oi: %{default: 0, type: :number, description: "Minimum OI to include"},
    enrich_limit: %{
      default: 50,
      type: :integer,
      description: "Max instruments to enrich"
    },
    top_n: %{
      default: nil,
      type: :integer,
      description: "Return only top N walls"
    }
  },
  params: %{
    exchange: %{
      description: "Built `%Bourse.Exchange{}` handle from `Bourse.exchange(:deribit)`",
      kind: :value
    },
    ccxt: %{
      description: "Bourse dispatcher module (the top-level `Bourse` module)",
      kind: :value
    }
  },
  errors: [
    no_spot_price: "Spot extracted from chain is <= 0",
    exchange_error: "Pass-through error from chain/2 or exchange module"
  ],
  returns: %{
    type: :tuple,
    description: "{:ok, %{walls, spot, chain_size, enriched_count}} or {:error, reason}"
  },
  returns_example: {:ok,
   %{
     spot: 83500.0,
     enriched_count: 50,
     walls: [%{type: :support, strike: 84000.0, gex: 1250.0}],
     chain_size: 120
   }}
}
```

# `option_type`

```elixir
@spec option_type(String.t()) :: {:ok, :call | :put} | {:error, :invalid_format}
```

Extract option type (:call or :put) from a Deribit option symbol.

## Parameters

  * `symbol` - Deribit option symbol (value)

## Returns

\{:ok, :call | :put\} or \{:error, :invalid_format\} (`tuple`)

### Example

```elixir
{:ok, :call}
```

## Errors

  * `:invalid_format`

```elixir
# descripex:contract
%{
  params: %{symbol: %{description: "Deribit option symbol", kind: :value}},
  errors: [:invalid_format],
  returns: %{
    type: :tuple,
    description: "{:ok, :call | :put} or {:error, :invalid_format}"
  },
  returns_example: {:ok, :call}
}
```

# `parse_dvol`

```elixir
@spec parse_dvol(term()) ::
  {:ok, dvol_result()} | {:error, :empty_history | :invalid_input}
```

Parse raw DVOL volatility index history into structured data.

## Parameters

  * `history_data` - List of DVOL rows, all of one of these shapes: five-element OHLC candles [unix_ms, open, high, low, close] as returned by Deribit's public/get_volatility_index_data (the close is taken as the value), two-element [unix_ms, value] pairs, or parsed volatility-history maps/structs with :timestamp and :volatility. Any other row shape rejects the whole payload as :invalid_input rather than being silently dropped. (value)

## Returns

\{:ok, %\{current, history\}\} or \{:error, :empty_history | :invalid_input\} (`tuple`)

### Example

```elixir
{:ok, %{history: [{~U[2026-02-25 12:00:00Z], 44.8}], current: 45.2}}
```

## Errors

  * `:empty_history` - The list was empty — the venue returned no rows
  * `:invalid_input` - Not a list, or a row whose shape is none of the accepted ones (unrecognised arity, non-numeric field, or a timestamp that is not a representable epoch millisecond)

```elixir
# descripex:contract
%{
  params: %{
    history_data: %{
      description: "List of DVOL rows, all of one of these shapes: five-element OHLC candles [unix_ms, open, high, low, close] as returned by Deribit's public/get_volatility_index_data (the close is taken as the value), two-element [unix_ms, value] pairs, or parsed volatility-history maps/structs with :timestamp and :volatility. Any other row shape rejects the whole payload as :invalid_input rather than being silently dropped.",
      kind: :value
    }
  },
  errors: [
    empty_history: "The list was empty — the venue returned no rows",
    invalid_input: "Not a list, or a row whose shape is none of the accepted ones (unrecognised arity, non-numeric field, or a timestamp that is not a representable epoch millisecond)"
  ],
  returns: %{
    type: :tuple,
    description: "{:ok, %{current, history}} or {:error, :empty_history | :invalid_input}"
  },
  returns_example: {:ok,
   %{history: [{~U[2026-02-25 12:00:00Z], 44.8}], current: 45.2}}
}
```

# `parse_option`

```elixir
@spec parse_option(String.t()) :: {:ok, parsed_option()} | {:error, :invalid_format}
```

Parse a Deribit option symbol into structured data.

## Parameters

  * `symbol` - Deribit option symbol (e.g., "BTC-31JAN26-84000-C") (value)

## Returns

\{:ok, %\{underlying, expiry, strike, type\}\} or \{:error, :invalid_format\} (`tuple`)

### Example

```elixir
{:ok,
 %{type: :call, strike: 84000.0, expiry: ~D[2026-01-31], underlying: "BTC"}}
```

## Errors

  * `:invalid_format`

## Composes With

  * `strike`
  * `expiry`
  * `option_type`
  * `underlying`
  * `valid_option?`

```elixir
# descripex:contract
%{
  params: %{
    symbol: %{
      description: "Deribit option symbol (e.g., \"BTC-31JAN26-84000-C\")",
      kind: :value
    }
  },
  errors: [:invalid_format],
  returns: %{
    type: :tuple,
    description: "{:ok, %{underlying, expiry, strike, type}} or {:error, :invalid_format}"
  },
  returns_example: {:ok,
   %{type: :call, strike: 84000.0, expiry: ~D[2026-01-31], underlying: "BTC"}},
  composes_with: [:strike, :expiry, :option_type, :underlying, :valid_option?]
}
```

# `parse_option!`

```elixir
@spec parse_option!(String.t()) :: parsed_option()
```

Parse a Deribit option symbol, raising on failure.

## Parameters

  * `symbol` - Deribit option symbol (value)

## Returns

%\{underlying, expiry, strike, type\} or raises ArgumentError (`map`)

### Example

```elixir
%{value: 1.0}
```

```elixir
# descripex:contract
%{
  params: %{symbol: %{description: "Deribit option symbol", kind: :value}},
  returns: %{
    type: :map,
    description: "%{underlying, expiry, strike, type} or raises ArgumentError"
  },
  returns_example: %{value: 1.0}
}
```

# `strike`

```elixir
@spec strike(String.t()) :: {:ok, float()} | {:error, :invalid_format}
```

Extract strike price from a Deribit option symbol.

## Parameters

  * `symbol` - Deribit option symbol (value)

## Returns

\{:ok, float()\} or \{:error, :invalid_format\} (`tuple`)

### Example

```elixir
{:ok, 84000.0}
```

## Errors

  * `:invalid_format`

```elixir
# descripex:contract
%{
  params: %{symbol: %{description: "Deribit option symbol", kind: :value}},
  errors: [:invalid_format],
  returns: %{
    type: :tuple,
    description: "{:ok, float()} or {:error, :invalid_format}"
  },
  returns_example: {:ok, 84000.0}
}
```

# `underlying`

```elixir
@spec underlying(String.t()) :: {:ok, String.t()} | {:error, :invalid_format}
```

Extract underlying asset from a Deribit option symbol.

## Parameters

  * `symbol` - Deribit option symbol (value)

## Returns

\{:ok, String.t()\} or \{:error, :invalid_format\} (`tuple`)

### Example

```elixir
{:ok, "BTC"}
```

## Errors

  * `:invalid_format`

```elixir
# descripex:contract
%{
  params: %{symbol: %{description: "Deribit option symbol", kind: :value}},
  errors: [:invalid_format],
  returns: %{
    type: :tuple,
    description: "{:ok, String.t()} or {:error, :invalid_format}"
  },
  returns_example: {:ok, "BTC"}
}
```

# `valid_option?`

```elixir
@spec valid_option?(String.t()) :: boolean()
```

Check if a symbol is a valid Deribit option format.

## Parameters

  * `symbol` - String to validate (value)

## Returns

true if valid Deribit option symbol (`boolean`)

### Example

```elixir
true
```

```elixir
# descripex:contract
%{
  params: %{symbol: %{description: "String to validate", kind: :value}},
  returns: %{type: :boolean, description: "true if valid Deribit option symbol"},
  returns_example: true
}
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
