ZenQuant.Options.Pricing.Lattice (zen_quant v0.7.0)

Copy Markdown View Source

Cox-Ross-Rubinstein lattice pricing for vanilla European and American options.

The named consumer is the zen_quant operator, for comparing early-exercise values with the European Black-Scholes-Merton prices in ZenQuant.Options.Pricing.

Supported contract

price/4 supports :call and :put payoffs with either :european exercise at expiry or :american exercise at every lattice step. Rates are annualized and continuously compounded. Dividends or carry are represented by a continuous annual :dividend_yield; discrete cash dividends are not modeled. Time is a caller-supplied year fraction, with no calendar convention imposed.

The caller controls convergence through the step count, which defaults to

  1. The implementation uses O(steps) memory and O(steps²) time. At expiry it returns intrinsic value. Zero volatility is evaluated as a deterministic path, avoiding a degenerate up/down tree.

The input map uses the same fields and units as ZenQuant.Options.Pricing: positive :spot and :strike, non-negative :time_to_expiry_years and :volatility, and numeric :risk_free_rate and :dividend_yield.

API Functions

FunctionArityDescriptionParam Kinds
price4Price a vanilla European or American option with a CRR lattice.option_type: value, exercise: value, inputs: value, steps: value

Summary

Types

Lattice pricing failure reason.

Exercise convention supported by the lattice.

CRR input map using continuous annual rates and a caller-supplied year fraction.

Vanilla option side.

Functions

Price a vanilla European or American option with a CRR lattice.

Types

error_reason()

@type error_reason() ::
  {:invalid_option_type, term()}
  | {:invalid_exercise, term()}
  | {:missing_input, atom()}
  | {:invalid_input, atom()}
  | {:invalid_lattice, map()}

Lattice pricing failure reason.

exercise()

@type exercise() :: :european | :american

Exercise convention supported by the lattice.

inputs()

@type inputs() :: %{
  spot: number(),
  strike: number(),
  time_to_expiry_years: number(),
  risk_free_rate: number(),
  dividend_yield: number(),
  volatility: number()
}

CRR input map using continuous annual rates and a caller-supplied year fraction.

option_type()

@type option_type() :: :call | :put

Vanilla option side.

Functions

price(option_type, exercise, inputs, steps \\ 500)

@spec price(
  option_type() | term(),
  exercise() | term(),
  inputs() | term(),
  pos_integer() | term()
) ::
  {:ok, float()} | {:error, error_reason()}

Price a vanilla European or American option with a CRR lattice.

Parameters

  • option_type - :call or :put (value)
  • exercise - :european or :american (value)
  • inputs - Map with positive :spot/:strike, time in years, continuous annual rates/yield, and annual decimal volatility (value)
  • steps - Positive CRR step count controlling convergence and runtime (default: 500, value)

Returns

{:ok, price} in spot currency units or {:error, reason} (result_tuple)

Example

{:ok, 9.223118455216966}

Errors

  • :invalid_option_type - Option type is not :call or :put
  • :invalid_exercise - Exercise convention is not :european or :american
  • :missing_input - A required map field is absent
  • :invalid_input - A field or step count has an unsupported type or domain
  • :invalid_lattice - Inputs imply a risk-neutral probability outside zero to one
# descripex:contract
%{
  params: %{
    option_type: %{description: "`:call` or `:put`", kind: :value},
    exercise: %{description: "`:european` or `:american`", kind: :value},
    inputs: %{
      description: "Map with positive :spot/:strike, time in years, continuous annual rates/yield, and annual decimal volatility",
      kind: :value
    },
    steps: %{
      default: 500,
      description: "Positive CRR step count controlling convergence and runtime",
      kind: :value
    }
  },
  errors: [
    invalid_option_type: "Option type is not :call or :put",
    invalid_exercise: "Exercise convention is not :european or :american",
    missing_input: "A required map field is absent",
    invalid_input: "A field or step count has an unsupported type or domain",
    invalid_lattice: "Inputs imply a risk-neutral probability outside zero to one"
  ],
  returns: %{
    type: :result_tuple,
    description: "`{:ok, price}` in spot currency units or `{:error, reason}`"
  },
  returns_example: {:ok, 9.223118455216966}
}