Current section
Files
Jump to
Current section
Files
lib/ccxt/trading/options/deribit.ex
defmodule CCXT.Trading.Options.Deribit do
@moduledoc """
Deribit option symbol parsing utilities.
Parses Deribit-format option symbols like "BTC-31JAN26-84000-C" into
structured data for analysis.
## Example
CCXT.Trading.Options.Deribit.parse_option("BTC-31JAN26-84000-C")
# => {:ok, %{underlying: "BTC", expiry: ~D[2026-01-31], strike: 84000.0, type: :call}}
CCXT.Trading.Options.Deribit.parse_option("ETH-28MAR25-2500-P")
# => {:ok, %{underlying: "ETH", expiry: ~D[2025-03-28], strike: 2500.0, type: :put}}
"""
@months_map %{
"JAN" => 1,
"FEB" => 2,
"MAR" => 3,
"APR" => 4,
"MAY" => 5,
"JUN" => 6,
"JUL" => 7,
"AUG" => 8,
"SEP" => 9,
"OCT" => 10,
"NOV" => 11,
"DEC" => 12
}
# Pattern: UNDERLYING-DDMMMYY-STRIKE-TYPE
# Examples: BTC-31JAN26-84000-C, ETH-28MAR25-2500-P
@symbol_pattern ~r/^([A-Z]+)-(\d{1,2})([A-Z]{3})(\d{2})-(\d+)-([CP])$/
@typedoc "Parsed option symbol data"
@type parsed_option :: %{
underlying: String.t(),
expiry: Date.t(),
strike: float(),
type: :call | :put
}
@doc """
Parse a Deribit option symbol into structured data.
## Parameters
* `symbol` - Deribit option symbol (e.g., "BTC-31JAN26-84000-C")
## Returns
* `{:ok, parsed}` - Successfully parsed option data
* `{:error, :invalid_format}` - Symbol doesn't match expected format
## Example
iex> CCXT.Trading.Options.Deribit.parse_option("BTC-31JAN26-84000-C")
{:ok, %{underlying: "BTC", expiry: ~D[2026-01-31], strike: 84000.0, type: :call}}
iex> CCXT.Trading.Options.Deribit.parse_option("invalid")
{:error, :invalid_format}
"""
@spec parse_option(String.t()) :: {:ok, parsed_option()} | {:error, :invalid_format}
def parse_option(symbol) when is_binary(symbol) do
case Regex.run(@symbol_pattern, symbol) do
[_full, underlying, day, month_str, year, strike, type] ->
with {:ok, expiry} <- parse_expiry(day, month_str, year),
{:ok, option_type} <- parse_type(type) do
{:ok,
%{
underlying: underlying,
expiry: expiry,
strike: String.to_integer(strike) * 1.0,
type: option_type
}}
end
nil ->
{:error, :invalid_format}
end
end
@doc """
Parse a Deribit option symbol, raising on failure.
Same as `parse_option/1` but raises `ArgumentError` on invalid format.
## Example
iex> CCXT.Trading.Options.Deribit.parse_option!("BTC-31JAN26-84000-C")
%{underlying: "BTC", expiry: ~D[2026-01-31], strike: 84000.0, type: :call}
"""
@spec parse_option!(String.t()) :: parsed_option()
def parse_option!(symbol) when is_binary(symbol) do
case parse_option(symbol) do
{:ok, parsed} -> parsed
{:error, :invalid_format} -> raise ArgumentError, "Invalid option symbol: #{symbol}"
end
end
@doc """
Extract strike price from a Deribit option symbol.
## Example
iex> CCXT.Trading.Options.Deribit.strike("BTC-31JAN26-84000-C")
{:ok, 84000.0}
"""
@spec strike(String.t()) :: {:ok, float()} | {:error, :invalid_format}
def strike(symbol) when is_binary(symbol) do
case parse_option(symbol) do
{:ok, %{strike: strike}} -> {:ok, strike}
error -> error
end
end
@doc """
Extract expiry date from a Deribit option symbol.
## Example
iex> CCXT.Trading.Options.Deribit.expiry("BTC-31JAN26-84000-C")
{:ok, ~D[2026-01-31]}
"""
@spec expiry(String.t()) :: {:ok, Date.t()} | {:error, :invalid_format}
def expiry(symbol) when is_binary(symbol) do
case parse_option(symbol) do
{:ok, %{expiry: expiry}} -> {:ok, expiry}
error -> error
end
end
@doc """
Extract option type (:call or :put) from a Deribit option symbol.
## Example
iex> CCXT.Trading.Options.Deribit.option_type("BTC-31JAN26-84000-C")
{:ok, :call}
"""
@spec option_type(String.t()) :: {:ok, :call | :put} | {:error, :invalid_format}
def option_type(symbol) when is_binary(symbol) do
case parse_option(symbol) do
{:ok, %{type: type}} -> {:ok, type}
error -> error
end
end
@doc """
Extract underlying asset from a Deribit option symbol.
## Example
iex> CCXT.Trading.Options.Deribit.underlying("BTC-31JAN26-84000-C")
{:ok, "BTC"}
"""
@spec underlying(String.t()) :: {:ok, String.t()} | {:error, :invalid_format}
def underlying(symbol) when is_binary(symbol) do
case parse_option(symbol) do
{:ok, %{underlying: underlying}} -> {:ok, underlying}
error -> error
end
end
@doc """
Check if a symbol is a valid Deribit option format.
## Example
iex> CCXT.Trading.Options.Deribit.valid_option?("BTC-31JAN26-84000-C")
true
iex> CCXT.Trading.Options.Deribit.valid_option?("BTC/USDT")
false
"""
@spec valid_option?(String.t()) :: boolean()
def valid_option?(symbol) when is_binary(symbol) do
match?({:ok, _}, parse_option(symbol))
end
# Parse expiry date from day, month string, and 2-digit year
@doc false
defp parse_expiry(day, month_str, year) do
month = Map.get(@months_map, month_str)
if month do
day_int = String.to_integer(day)
# Assume 20xx century for 2-digit years
year_int = 2000 + String.to_integer(year)
case Date.new(year_int, month, day_int) do
{:ok, date} -> {:ok, date}
{:error, _} -> {:error, :invalid_format}
end
else
{:error, :invalid_format}
end
end
# Parse option type from C/P suffix
@doc false
defp parse_type("C"), do: {:ok, :call}
defp parse_type("P"), do: {:ok, :put}
end