# `DeltaCalc.DeltaNeutral`
[🔗](https://github.com/ZenHive/delta_calc/blob/v0.3.0/lib/delta_calc/delta_neutral.ex#L1)

Base-numeraire exposure, settlement coverage, and delta-neutral rebalance math.

Tagged option and inverse-perpetual inputs preserve provider unit semantics.
Coverage and risk-target evaluation remain separate calculations and never
produce an approval decision. This module does not price options or compute Greeks.

## API Functions
| Function | Arity | Description | Param Kinds |
| --- | --- | --- | --- |
| `rebalance_to_neutral` | 1 | Compute the hedge leg needed to flatten net delta within a tolerance. | `params: value` |
| `net_delta` | 1 | Aggregate signed delta exposure across spot, perp, and option positions. | `positions: value` |
| `risk_target` | 1 | Evaluate signed base-numeraire exposure against a caller-supplied target and tolerance. | `params: value` |
| `settlement_coverage` | 1 | Calculate covered-call settlement capacity from caller-classified, disjoint base amounts. | `params: value` |
| `base_numeraire_exposure` | 1 | Calculate signed base exposure from explicitly tagged option or inverse-perpetual facts. | `params: value` |

# `calculation_error`

```elixir
@type calculation_error() ::
  exposure_error()
  | :invalid_coverage_shape
  | :invalid_risk_target_shape
  | :negative_coverage_amount
```

# `coverage_params`

```elixir
@type coverage_params() :: %{
  eligible_base: DeltaCalc.Decimal.input(),
  existing_short_call_obligations: DeltaCalc.Decimal.input(),
  pending_sell_reservations: DeltaCalc.Decimal.input(),
  other_reservations: DeltaCalc.Decimal.input(),
  proposed_short_call_obligation: DeltaCalc.Decimal.input()
}
```

# `coverage_result`

```elixir
@type coverage_result() :: %{
  eligible_base: Decimal.t(),
  existing_reservations: %{
    short_call_obligations: Decimal.t(),
    pending_sell_reservations: Decimal.t(),
    other_reservations: Decimal.t(),
    total: Decimal.t()
  },
  proposed_short_call_obligation: Decimal.t(),
  total_obligation: Decimal.t(),
  remaining_capacity: Decimal.t(),
  uncovered_amount: Decimal.t(),
  fully_covered: boolean()
}
```

# `exposure_error`

```elixir
@type exposure_error() ::
  :ambiguous_settlement_input
  | :invalid_decimal
  | :invalid_delta_shape
  | :invalid_mark_shape
  | :invalid_quantity_shape
  | :mixed_delta_shape
  | :mixed_mark_shape
  | :mixed_quantity_shape
  | :non_positive_mark
  | :non_positive_spot
  | :unsupported_delta_semantic
  | :unsupported_exposure_kind
  | :unsupported_exposure_period
  | :unsupported_mark_unit
  | :unsupported_quantity_unit
  | :untagged_delta_semantic
  | :untagged_exposure_kind
  | :untagged_mark_unit
  | :untagged_quantity_unit
```

# `exposure_params`

```elixir
@type exposure_params() :: map()
```

# `position`

```elixir
@type position() :: %{
  :kind =&gt; position_kind(),
  optional(:size) =&gt; DeltaCalc.Decimal.input(),
  optional(:notional) =&gt; DeltaCalc.Decimal.input(),
  optional(:side) =&gt; position_side(),
  optional(:delta) =&gt; DeltaCalc.Decimal.input()
}
```

# `position_kind`

```elixir
@type position_kind() :: :spot | :perp | :option
```

# `position_side`

```elixir
@type position_side() :: :long | :short
```

# `rebalance_params`

```elixir
@type rebalance_params() :: %{
  :positions =&gt; [position()],
  optional(:tolerance) =&gt; DeltaCalc.Decimal.input(),
  optional(:instrument) =&gt; :spot | :perp
}
```

# `rebalance_result`

```elixir
@type rebalance_result() :: %{
  net_delta: Decimal.t(),
  within_tolerance: boolean(),
  side: :long | :short | :none,
  size: Decimal.t(),
  instrument: :spot | :perp,
  signed_hedge: Decimal.t()
}
```

# `risk_target_params`

```elixir
@type risk_target_params() :: %{
  base_numeraire_exposure: DeltaCalc.Decimal.input(),
  target_exposure: DeltaCalc.Decimal.input(),
  tolerance: DeltaCalc.Decimal.input()
}
```

# `risk_target_result`

```elixir
@type risk_target_result() :: %{
  base_numeraire_exposure: Decimal.t(),
  target_exposure: Decimal.t(),
  tolerance: Decimal.t(),
  residual_exposure: Decimal.t(),
  within_target: boolean()
}
```

# `base_numeraire_exposure`

```elixir
@spec base_numeraire_exposure(exposure_params()) ::
  {:ok, Decimal.t()} | {:error, exposure_error()}
```

Return signed base exposure from one explicitly tagged option or inverse-perpetual input.

# `net_delta`

```elixir
@spec net_delta([position()]) :: Decimal.t()
```

Sum signed delta exposure across `positions`.

Option positions must include exchange-supplied `:delta` (not computed here).
Spot and perp positions use `:delta` when present; otherwise derive signed
exposure from `:size` or `:notional` and `:side` (default `:long`).

# `rebalance_to_neutral`

```elixir
@spec rebalance_to_neutral(rebalance_params() | [position()]) :: rebalance_result()
```

Return the hedge adjustment to bring net delta to ~0 within `tolerance`.

When already within tolerance, `:side` is `:none` and `:size` is zero.
`:signed_hedge` is sized for `DeltaCalc.Hedging.suggest_hedge_distribution/1`.

# `risk_target`

```elixir
@spec risk_target(risk_target_params()) ::
  {:ok, risk_target_result()} | {:error, calculation_error()}
```

Return the signed residual from a target and whether it is within absolute tolerance.

# `settlement_coverage`

```elixir
@spec settlement_coverage(coverage_params()) ::
  {:ok, coverage_result()} | {:error, calculation_error()}
```

Return settlement capacity after existing disjoint reservations and a proposed obligation.

---

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