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

Pure funding-rate math: APR annualisation, cross-venue comparison, arbitrage
detection, and trend analysis.

All functions take caller-supplied `Decimal` rates — no exchange clients or I/O.

## API Functions
| Function | Arity | Description | Param Kinds |
| --- | --- | --- | --- |
| `funding_trend` | 1 | Analyse a funding-rate time series for direction, slope, and volatility. | `series: value` |
| `find_arbitrage_opportunities` | 2 | Find cross-venue funding spreads that exceed a minimum delta threshold. | `comparison: value`, `min_delta: value` |
| `compare_funding_rates` | 2 | Compare venue funding rates for one or more symbols and rank venues by rate. | `rates: value`, `periods_per_day: value` |
| `funding_apr` | 2 | Annualise a per-period funding rate into hourly, daily, and annual percentages. | `rate: value`, `period_hours: value` |

# `apr_result`

```elixir
@type apr_result() :: %{hourly: Decimal.t(), daily: Decimal.t(), annual: Decimal.t()}
```

Annualised funding-rate breakdown as percentage Decimals.

# `comparison_result`

```elixir
@type comparison_result() :: %{
  optional(:insufficient_data) =&gt; true,
  optional(:arbitrage_opportunity) =&gt; boolean(),
  optional(:delta) =&gt; Decimal.t(),
  optional(:delta_unit) =&gt; delta_unit(),
  optional(:max_exchange) =&gt; atom(),
  optional(:min_exchange) =&gt; atom(),
  optional(:annual_apr_delta) =&gt; Decimal.t(),
  optional(:ranked) =&gt; [{atom(), Decimal.t()}]
}
```

Per-symbol cross-venue funding comparison.

# `decimal_input`

```elixir
@type decimal_input() :: DeltaCalc.Decimal.input()
```

# `delta_unit`

```elixir
@type delta_unit() :: :raw_per_period | :daily_normalized
```

# `periods_per_day_input`

```elixir
@type periods_per_day_input() ::
  decimal_input() | %{required(atom()) =&gt; decimal_input()}
```

# `trend_result`

```elixir
@type trend_result() :: %{
  avg_rate: Decimal.t(),
  max_rate: Decimal.t(),
  min_rate: Decimal.t(),
  trend: :increasing | :decreasing | :flat,
  slope: Decimal.t(),
  volatility: Decimal.t(),
  data_points: non_neg_integer()
}
```

Funding trend summary from a rate series.

# `compare_funding_rates`

```elixir
@spec compare_funding_rates(map(), periods_per_day_input()) ::
  map() | comparison_result()
```

Compare funding rates across venues.

Pass `%{binance: rate, bybit: rate}` for one symbol, or
`%{"BTCUSDT" => %{binance: rate, bybit: rate}}` for many.
`periods_per_day` defaults to 3 for 8-hour funding; pass 24 for Deribit
hourly funding or `%{venue => periods}` when venues use different cadences.
Each result tags `delta_unit`. With a scalar cadence, `delta` is a raw
per-period spread (`:raw_per_period`) for unchanged 8-hour/24-hour behavior.
With a venue cadence map, venues are ranked by per-day-normalized rate
(`rate * periods_per_day`), `delta` is that daily-normalized spread
(`:daily_normalized`), `annual_apr_delta` is the daily spread annualized to
APR percentage points, and the arbitrage threshold is the default 8-hour raw
threshold normalized to daily terms (`0.0005 * 3 = 0.0015`).

# `find_arbitrage_opportunities`

```elixir
@spec find_arbitrage_opportunities(map(), decimal_input()) :: [map()]
```

Return arbitrage opportunities from a comparison map, filtered by `min_delta`.

`min_delta` keeps the legacy scalar raw-period threshold scale. Entries tagged
`:daily_normalized` compare against `min_delta` multiplied by the default
periods per day so scalar- and map-cadence comparison results can be filtered
together without scale skew.

# `funding_apr`

```elixir
@spec funding_apr(decimal_input(), pos_integer()) ::
  {:ok, apr_result()} | {:error, :invalid_rate}
```

Convert a per-period funding rate into hourly, daily, and annual percentage APR.

# `funding_trend`

```elixir
@spec funding_trend(list()) :: {:ok, trend_result()} | {:error, :insufficient_data}
```

Summarise a funding-rate series with trend direction and half-series slope.

---

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