---
title: "3.7.2 Funding, basis and cross-exchange arbitrage"
description: "Cash-and-carry with perpetuals and quarterlies, the short leg's margin, differences between exchanges and one exchange's failure as counterparty risk."
url: "https://pythonparatrading.com/en/python-trading-course/level-3/funding-basis-cross-exchange-arbitrage/"
lang: "en"
image: "https://pythonparatrading.com/og/en/python-trading-course/level-3/funding-basis-cross-exchange-arbitrage.png"
---

# 3.7.2 · Funding arbitrage, basis with futures and cross-exchange arbitrage

> The cash-and-carry collects the perpetual's funding or locks in the quarterly's basis without betting on the price. This lesson measures how much it paid on four synthetic exchanges and how much it narrowed, what it costs in margin and liquidations, when locking in the basis pays off and what is left of it all when the exchange that paid the most goes bankrupt.

- Course: [Level 3: Derivatives: futures, spreads, forex and options](https://pythonparatrading.com/en/python-trading-course/level-3/)
- Module: 3.7 · Crypto derivatives and specific strategies
- Duration: 75 min
- Prerequisites: [2.3.7 · Crypto-specific strategies: momentum, funding arbitrage and basis](https://pythonparatrading.com/en/python-trading-course/level-2/crypto-momentum-funding-basis-strategies/), [2.4.7 · Cost modeling: commissions, bid-ask spread, impact, financing and securities borrowing](https://pythonparatrading.com/en/python-trading-course/level-2/backtest-transaction-cost-modeling/), [3.7.1 · Perpetuals: funding mechanics, mark price and liquidations](https://pythonparatrading.com/en/python-trading-course/level-3/perpetual-futures-funding-mark-price-liquidations/)

## By the end of this lesson

- Measure the perpetual's carry by exchange, asset and year, separate the floor set by the funding formula from the market premium and estimate how much that premium narrows.
- Size the short leg: return on capital, liquidations depending on leverage and rebalancing frequency, and days of carry that entering and exiting costs.
- Measure the basis of the quarterlies, compare it with the funding collected in the same quarter and decide between locking it in or letting it float without looking at the future.
- Distinguish the funding differential between exchanges from a price dislocation and explain what is needed to exploit each one.
- Quantify counterparty risk with the planted bankruptcy of dedalo and relate it to what the CFTC and SEC complaints about FTX document.

## Three ways to collect the carry

Lesson 2.3.7 introduced the cash-and-carry: buy the coin spot and sell the same quantity in a derivative, so that the
price does not matter and the carry remains. With the level 3 data it can be done with four exchanges and two assets,
with perpetuals and with quarterlies, and measure what lesson 2.3.7 only listed: how much margin the short leg needs,
when it is liquidated, when the future pays off and what happens when the exchange goes bankrupt. There are three
variants:

```mermaid
flowchart TB
  C[Long spot] --> P[Short perpetual]
  C --> T[Short quarterly]
  C --> O[Perp. other exch.]
  P --> F[Variable funding]
  T --> B[Locked-in basis]
  O --> R[Two counterparties]
```

- **With the perpetual.** It collects each period's funding, which changes and can turn negative.
- **With the quarterly.** The basis is locked in at opening: at expiry the future settles to the index and the result
  is the initial difference, whatever funding does.
- **Split across exchanges.** The spot on one and the derivative on another, or the derivative on the one that pays
  the most. It gains some carry or margin and adds a counterparty.

<aside class="callout" data-kind="aviso">

The data is **synthetic** (lesson 3.7.1): XBQ and XEQ mimic BTC and ETH; `alfa`, `boreal`, `cenit` and `dedalo` mimic
Binance, Deribit, BitMEX and FTX. The perpetual's premium, its narrowing, the basis, the dislocations and the
bankruptcy of `dedalo` are planted with known parameters. No return from this data is evidence that a strategy works
in real markets. The facts of the FTX case come from the CFTC and SEC complaints (in the resources), which are the
regulators' allegations.

</aside>

```python
import numpy as np
import pandas as pd

fu = pd.read_parquet("cripto3_funding.parquet")
carry = (100 * fu.groupby(["activo", "exchange",
                           fu["ts"].dt.year])["tasa_funding"]
         .sum()).unstack()
print("funding collected by the short, % of notional per year:")
print(carry.round(1).to_string())
suelo = 100 * 0.0001 * 3 * 365
print(f"floor of the interest term: {suelo:.2f}% a year")
```
```output
funding collected by the short, % of notional per year:
ts               2020  2021  2022  2023  2024  2025
activo exchange
XBQ    alfa      25.6  24.4  10.4  11.8  11.2   9.7
       boreal    28.7  26.4  11.4  13.3  12.2  10.5
       cenit     23.7  23.0   8.8  10.8   9.9   8.8
       dedalo    29.8  28.7   7.5   NaN   NaN   NaN
XEQ    alfa      52.9  38.3  11.7  12.4  10.9   9.4
       boreal    55.5  40.0  13.4  13.8  11.9  10.4
       cenit     49.9  35.6   9.6  11.8  10.2   8.6
       dedalo    59.5  42.8  10.1   NaN   NaN   NaN
floor of the interest term: 10.95% a year
```

The table is what the perpetual's short collected each year, in % of notional, without costs or compounding. For XBQ,
from 23.0% to 29.8% in 2020 and 2021 depending on the exchange; since 2022, between 8.8% and 13.3% on the three that
survive. XEQ pays double in the years of euphoria (from 49.9% to 59.5% in 2020) and almost the same as XBQ afterwards.
The figure at the top draws the XBQ lines. Two things stand out: `dedalo` is the one that pays the most while it
exists, and since 2022 all the others stick to the **10.95% floor** set by the formula's interest term
($0.01\,\% \times 3 \times 365$, lesson 3.7.1).

That floor deserves attention. It is not the dollar interest rate or the result of supply and demand: it is a constant
of the exchange's formula, the one a long pays while the premium is inside the band. The “market” carry is what lies
above it, and in the data it is planted as a bullish premium that narrows with a half-life of 2.5 years (more capital
devoted to arbitraging it). Is that half-life recovered?

```python
from scipy.optimize import curve_fit

a = fu[(fu["exchange"] == "alfa") & (fu["activo"] == "XBQ")]
a = a.set_index("ts")
r7 = np.log(a["precio_indice"] / a["precio_indice"].shift(21))
z = np.tanh(r7 / 0.15)                   # euphoria: z close to 1
d = pd.DataFrame({"prima": a["prima_media"], "z": z}).dropna()
d["anos"] = (d.index - d.index[0]).days / 365.25
eu = d[d["z"] > 0.5]


def prima_alcista(X, amp, vida):
    anos, z = X
    return amp * np.exp(-np.log(2) * anos / vida) * z ** 2


(amp, vida), _ = curve_fit(prima_alcista, (eu["anos"], eu["z"]),
                           eu["prima"], p0=[0.003, 2.0])
print(f"{len(eu)} euphoria periods; amplitude {1e4 * amp:.1f} bp,"
      f" half-life {vida:.2f} years")
print((1e4 * eu["prima"] / eu["z"] ** 2).groupby(eu.index.year)
      .mean().round(1).to_dict())
```
```output
1091 euphoria periods; amplitude 33.7 bp, half-life 2.53 years
{2020: 29.0, 2021: 23.1, 2022: 15.8, 2023: 14.2, 2024: 10.0, 2025: 7.2}
```

In the 1,091 periods of euphoria (high 7-day return, $\tanh(r_7/0.15) > 0.5$), a nonlinear fit recovers an amplitude of
33.7 basis points per period and a half-life of 2.53 years, versus the planted 35 and 2.5. The premium per unit of
euphoria falls from 29.0 basis points in 2020 to 7.2 in 2025. The data is not reality, but the direction matches what
He, Manela, Ross and von Wachter document: the deviations of perpetuals from their no-arbitrage price have been
shrinking over time[^1].

[^1]: S. He, A. Manela, O. Ross and V. von Wachter, “Fundamentals of Perpetual Futures”, arXiv 2212.06888 (version 1
from December 2022, revised later). The abstract says the deviations are larger than in currency markets, comove
across coins and shrink over time; the lesson does not cite figures from the paper.

## The short leg needs margin

The cash-and-carry has no price risk on paper, but the capital is not just the spot. The short leg needs margin, and
with isolated margin it is liquidated if the mark rises to its liquidation price, even if the spot has gained the same
(lesson 3.7.1). With leverage $L$ on that leg, the capital per unit of notional is $1 + 1/L$ and the return on capital,
the carry divided by that amount. More leverage raises the return and brings liquidation closer. The 1-hour bars of
`alfa` let us count how many times it would have happened if every week (or every month) the margin were topped up and
the short leg reopened at the price of that moment:

```python
h1 = pd.read_parquet("cripto3_1h.parquet")
b = h1[h1["activo"] == "XBQ"].set_index("ts")
f_alfa = a["tasa_funding"]
anual = f_alfa.sum() / ((f_alfa.index[-1] - f_alfa.index[0]).days
                        / 365.25)
MMR = 0.005
filas = []
for L in (1, 2, 3, 5, 10, 20):
    fila = {"apal_corto": L,
            "rend_capital_pct": 100 * anual / (1 + 1 / L)}
    for nombre, frec in (("semanal", "7D"), ("mensual", "30D")):
        g = b.groupby(pd.Grouper(freq=frec))
        liq = g["apertura"].first() * (1 + 1 / L) / (1 + MMR)
        fila[f"liq_{nombre}"] = int((g["mark_maximo"].max() >= liq)
                                    .sum())
    filas.append(fila)
print(f"average carry on alfa, XBQ: {100 * anual:.1f}% of notional")
pd.DataFrame(filas).set_index("apal_corto").round(1)
```
```output
average carry on alfa, XBQ: 15.5% of notional
            rend_capital_pct  liq_semanal  liq_mensual
apal_corto
1                        7.8            0            0
2                       10.4            0            2
3                       11.6            1            9
5                       12.9            8           28
10                      14.1           71           52
20                      14.8          180           60
```

*Fig. — XBQ cash-and-carry on alfa by short-leg leverage: annual return on capital before costs and weeks in which the mark would have liquidated the short (weekly rebalancing, 2020-2025).* Six points joined by a line. At 1x the return on capital is 7.8% and at 2x 10.4%, without liquidations; at 3x, highlighted, 11.6% with one week liquidated; at 5x, 12.9% and 8 weeks; at 10x, 14.1% and 71; at 20x, 14.8% and 180 of 314 weeks. Each extra point of return costs more and more liquidations.

The average carry of XBQ on `alfa` is 15.5% a year of notional. Without leverage on the short (1x), the capital doubles
and the return falls to 7.8%; with 3x, 11.6%, and in six years the mark would have liquidated the short in only one
week; with 10x, 14.1%, but 71 weeks out of 314 end with the short liquidated and the spot unhedged. With monthly
rebalancing the risk grows at low leverage (9 liquidations at 3x versus 1): in 30 days the price has more time to rise
before the margin is topped up. The monthly figures at 10x and 20x are lower only because there are fewer months than
weeks. The chart sums up the trade-off: the last points of return are paid for with a number of liquidations that
grows much faster.

<aside class="callout" data-kind="riesgo">

A liquidation of the short leg is not a small loss: that leg's margin is lost and the spot is left exposed right after
a sharp rise, usually in a market with high funding and thin order books. Topping up margin requires selling spot or
bringing in cash **before** reaching maintenance, and moving funds between accounts or exchanges takes time. A
backtest that collects the carry without simulating the short leg's margin overestimates what is earned and hides the
worst moment.

</aside>

Costs count too. Entering and exiting pays four sides (buying and selling spot, selling and buying back the
perpetual). With an assumption of 5 basis points per side, on the order of the commission of a client taking liquidity
on a large exchange (lesson 2.4.7), it costs:

```python
COMISION = 5 / 1e4          # assumption: 5 bp per side and leg
lados = 4                   # buy and sell spot and perpetual
for nombre, diario in [("floor (0.03% daily)", 0.0003),
                       ("2025 average", carry.loc[("XBQ", "alfa"),
                                                  2025] / 100 / 365)]:
    dias = lados * COMISION / diario
    print(f"{nombre}: {dias:.1f} days of carry to pay for entry"
          " and exit")
```
```output
floor (0.03% daily): 6.7 days of carry to pay for entry and exit
2025 average: 7.5 days of carry to pay for entry and exit
```

About 7 days of carry at the floor, 7.5 at the 2025 pace. A cash-and-carry that is opened and closed often, for
example every time a week's funding drops (exercise of lesson 2.3.7), eats the carry in commissions.

## The basis of the quarterlies

`cripto3_futuros.parquet` has a daily snapshot, at 00:00 UTC, of the two nearest quarterlies of each exchange and
asset; they expire on the last Friday of March, June, September and December at 08:00 UTC. The annualized basis is
measured with the index at the same time, as $\ln(F/S) \times 365/\text{days}$:

```python
ft = pd.read_parquet("cripto3_futuros.parquet")
ind = (fu[fu["exchange"] == "alfa"]
       .set_index(["ts", "activo"])["precio_indice"])
ft = ft.join(ind, on=["ts", "activo"]).dropna(subset=["precio_indice"])
ft["basis"] = np.log(ft["precio"] / ft["precio_indice"]) * 365 \
    / ft["dias"]
vivos = ft[ft["exchange"] != "dedalo"]
err = 100 * (vivos["basis"] - vivos["basis_anual_modelo"]).abs()
print(f"error versus the model's (points): median {err.median():.4f}"
      f", maximum {err.max():.2f}, maximum beyond 10 days "
      f"{err[vivos['dias'] > 10].max():.2f}")
x = vivos[(vivos["exchange"] == "alfa") & (vivos["activo"] == "XBQ")]
orden = x.groupby("ts").cumcount()
primero, segundo = x[orden == 0], x[orden == 1]
print("average basis of the front quarterly, % a year:")
print((100 * primero.groupby(primero["ts"].dt.year)["basis"].mean())
      .round(1).to_dict())
dif = (segundo.set_index("ts")["basis"] - primero.set_index("ts")
       ["basis"])
print(f"second minus first: {100 * dif.mean():+.2f} points")
```
```output
error versus the model's (points): median 0.0029, maximum 1.33, maximum beyond 10 days 0.26
average basis of the front quarterly, % a year:
{2020: 22.3, 2021: 23.1, 2022: 10.9, 2023: 11.9, 2024: 11.1, 2025: 9.2}
second minus first: +0.40 points
```

The measured basis matches the model column with a median of 0.003 points; the maximum error, 1.33 annualized points,
appears in the last days before expiry, when the rounding of the price to the tick is multiplied by 365 divided by a
few days (beyond 10 days, 0.26). The average basis of the front XBQ quarterly on `alfa` is 22.3% and 23.1% in 2020 and
2021, and from 9.2% to 11.9% afterwards, in line with funding. The second quarterly trades 0.40 annualized points above
the first: the planted term premium.

The practical question is whether it pays to lock in the basis or collect the funding. For each quarterly, the
cash-and-carry is opened when it has about 95 days left and the locked-in basis (in % of notional for the whole
quarter) is compared with the funding the perpetual would have collected from that day until expiry:

```python
def trimestres(fut, fund):
    """Per contract: basis locked in at <= 95 days to expiry, funding
    collected until expiry and that of the previous 90 days (%)."""
    filas = []
    for contrato, c in fut.groupby("contrato"):
        ent = c[c["dias"] <= 95].head(1)
        if ent.empty:
            continue
        e0 = ent.iloc[0]
        t0 = e0["ts"]
        vto = (pd.Timestamp(e0["vencimiento"]).tz_localize("UTC")
               + pd.Timedelta(hours=8))
        if t0 < pd.Timestamp("2020-02-01", tz="UTC") or vto.year > 2025:
            continue
        hasta_vto = fund[(fund.index > t0) & (fund.index <= vto)].sum()
        previo = fund[(fund.index > t0 - pd.Timedelta(days=90))
                      & (fund.index <= t0)].sum()
        filas.append({"contrato": contrato,
                      "fijado": 100 * np.log(e0["precio"]
                                             / e0["precio_indice"]),
                      "funding": 100 * hasta_vto,
                      "funding_previo": 100 * previo})
    return pd.DataFrame(filas).set_index("contrato")


q = trimestres(x, f_alfa)
print(q.round(2).head(8).to_string())
print(f"{len(q)} quarters; locked-in mean {q['fijado'].mean():.2f}%,"
      f" funding collected {q['funding'].mean():.2f}%, correlation "
      f"{q['fijado'].corr(q['funding']):.2f}")
elige = np.where(q["fijado"] > q["funding_previo"], q["fijado"],
                 q["funding"])
print(f"rule “the larger of the two at opening”: {elige.mean():.2f}% "
      f"per quarter")
```
```output
            fijado  funding  funding_previo
contrato
XBQ-200626    2.04     8.94            2.81
XBQ-200925    2.15     4.49            8.81
XBQ-201225    1.23     8.87            4.37
XBQ-210326   11.98    14.12            8.52
XBQ-210625    1.00     3.76           13.68
XBQ-210924    2.51     4.05            3.73
XBQ-211231   15.55     2.90            4.75
XBQ-220325    3.58     2.27            4.19
23 quarters; locked-in mean 3.97%, funding collected 3.97%, correlation 0.24
rule “the larger of the two at opening”: 5.14% per quarter
```

*Fig. — Basis locked when opening a cash-and-carry with the quarterly future against the funding the perpetual would have collected over the same quarter (alfa, XBQ, 23 quarters).* For each quarter from 2020 to 2025, a dash with the locked basis and a dot with the funding collected, joined by a vertical line. Both hover around 2% to 4% per quarter from 2022 and are higher in 2020 and 2021; each quarter one beats the other by several points, with no pattern. The highlighted dash, the quarter expiring in December 2021, locks 15.6% while that quarter's funding only pays 2.9%. Means are equal: 3.97% per quarter.

Over 23 quarters, the mean of the locked-in basis is 3.97% per quarter and that of the funding collected, also 3.97%.
Locking in neither wins nor loses on average: it removes uncertainty. The correlation between the two is only 0.24, and
the figure shows why: in any given quarter one beats the other by several points. The quarterly expiring in December
2021 locked in 15.55% and that quarter's funding gave 2.90%; the one expiring in June 2020 locked in 2.04% while
funding gave 8.94%.

Since the basis in the data carries noise of its own that does not anticipate the next funding, a rule without
information from the future exploits it: lock in the basis if it is larger than the funding of the previous 90 days
and, if not, stay with the perpetual. It gives 5.14% per quarter. It is exercise 3; before believing it in real
markets one would need to check whether, there, the noise of the basis is independent of future funding, and with 23
observations per pair the standard error is large.

## Between exchanges: funding differentials and dislocations

Each exchange computes its funding with its own premium. If one systematically pays more than another, one can be
short the perpetual of the one that pays more and long that of the one that pays less, without spot: the funding
differential.

```python
p = fu[fu["activo"] == "XBQ"].pivot(index="ts", columns="exchange",
                                     values="tasa_funding")
dif = 100 * p.sub(p["alfa"], axis=0).drop(columns="alfa")
print("difference with alfa, percentage points per year:")
print(dif.groupby(dif.index.year).sum(min_count=1).round(2).T
      .to_string())
diferencial = p["boreal"] - p["cenit"]
print(f"periods in which boreal pays the same as cenit: "
      f"{100 * (diferencial.abs() < 1e-9).mean():.1f}%")
```
```output
difference with alfa, percentage points per year:
ts        2020  2021  2022  2023  2024  2025
exchange
boreal    3.03  1.99  1.05  1.42  0.98  0.86
cenit    -1.93 -1.44 -1.59 -1.05 -1.32 -0.87
dedalo    4.19  4.33 -1.72   NaN   NaN   NaN
periods in which boreal pays the same as cenit: 71.4%
```

`boreal` pays 3.03 points a year more than `alfa` in 2020 and 0.86 in 2025; `cenit`, between 0.87 and 1.93 less every
year; `dedalo`, 4.19 and 4.33 more in 2020 and 2021. The planted premium of each exchange is constant (half a basis
point more on `boreal`, half less on `cenit`), but the differential narrows every year. The reason is the formula's
band: in 71.4% of the periods `boreal` and `cenit` pay exactly the same, the fixed basis point. The difference in
premiums only passes into funding when the premium leaves the band, in the weeks of euphoria, and those are less and
less profitable. Exercise 2 computes what is left after costs.

**Dislocations** are something else: an exchange's spot price separates from the others' for a few hours. There are
four planted in the data; the published daily closes reveal two:

```python
cd = pd.read_parquet("cripto3_diario.parquet")
xb = cd[cd["activo"] == "XBQ"]
sp = xb.pivot(index="fecha", columns="exchange", values="cierre_spot")
ok = xb.pivot(index="fecha", columns="exchange",
              values="retiradas_abiertas")
indice = sp.where(ok == True).median(axis=1)
desv = 100 * np.log(sp.div(indice, axis=0))
for e in ["alfa", "boreal", "cenit"]:
    m = desv[e].abs()
    print(f"{e}: standard deviation {desv[e].std():.3f}%, worst day "
          f"{m.idxmax():%Y-%m-%d} ({desv[e][m.idxmax()]:+.2f}%)")
```
```output
alfa: standard deviation 0.092%, worst day 2025-10-10 (-3.96%)
boreal: standard deviation 0.035%, worst day 2020-01-23 (+0.14%)
cenit: standard deviation 0.122%, worst day 2020-03-12 (-5.45%)
```

Outside those days, each exchange's spot deviates from the index with a standard deviation of between 0.035% and
0.122%, less than any commission. The two large episodes are that of March 12, 2020 on `cenit` (−5.45%) and that of
October 10, 2025 on `alfa` (−3.96%), both in the middle of a sell-off. Exploiting them requires buying on the cheap
exchange and selling on the others at the same time, which can only be done with **inventory already in place** at
both venues: there is no time to move coins or dollars from one exchange to another while it lasts. And they happen
when order books are thinnest, withdrawals most congested and the risk that the cheap exchange has a real problem is
highest. A dislocation can be an opportunity or the first symptom of a bankruptcy.

## Counterparty risk: the bankruptcy of dedalo

`dedalo` was, until November 2022, the exchange that paid best. The timeline of its bankruptcy is in
`cripto3_exchanges.csv` and is inspired by that of FTX, without copying it:

```mermaid
stateDiagram-v2
  [*] --> Normal
  Normal --> Rumors: Nov 6
  Rumors --> Suspension: Nov 8 12:00
  Suspension --> Halt: Nov 11 14:00
  Halt --> Bankruptcy: Nov 11 23:00
  Bankruptcy --> [*]
```

With the suspension, withdrawals are closed and balances stop being convertible; the `dedalo` spot trades at a growing
discount and drops out of the index; funding turns very negative; at 14:00 on the 11th trading halts and, for the
course, balances and positions are worth zero.

```python
ded = (fu[(fu["exchange"] == "dedalo") & (fu["activo"] == "XBQ")]
       .set_index("ts"))
hasta = pd.Timestamp("2022-11-08 08:00", tz="UTC")
c_ded = ded["tasa_funding"][:hasta].sum()
c_alfa = f_alfa[:hasta].sum()
anos = (hasta - ded.index[0]).days / 365.25
print(f"cumulative carry until {hasta:%Y-%m-%d}: dedalo "
      f"{100 * c_ded:.1f}%, alfa {100 * c_alfa:.1f}% of notional")
print(f"dedalo premium: {100 * (c_ded - c_alfa) / anos:.2f} points"
      " a year")
ded[ded.index >= "2022-11-08"][["precio_indice", "ultimo",
                                "tasa_funding"]].head(7)
```
```output
cumulative carry until 2022-11-08: dedalo 69.3%, alfa 59.2% of notional
dedalo premium: 3.53 points a year
                           precio_indice   ultimo  tasa_funding
ts
2022-11-08 00:00:00+00:00        22086.5  22098.6      0.000100
2022-11-08 08:00:00+00:00        22055.8  22068.4      0.000100
2022-11-08 16:00:00+00:00        20037.7  20012.2     -0.002016
2022-11-09 00:00:00+00:00        19958.3  19190.9     -0.003800
2022-11-09 08:00:00+00:00        19623.3  18367.6     -0.002295
2022-11-09 16:00:00+00:00        21563.9  20084.3     -0.004368
2022-11-10 00:00:00+00:00        19746.2  17699.2     -0.003066
```

Until November 8, 2022, the short of the XBQ perpetual collected 69.3% of notional on `dedalo` and 59.2% on `alfa`: a
premium of 3.53 points a year for being on `dedalo`. The table shows how it ends. On the 8th at 16:00, four hours after
withdrawals were suspended, the `dedalo` perpetual already trades slightly below the index and funding is −0.20% per
period: now the shorts pay. The next day the discount is 3.8% and funding, −0.38%.

*Fig. — Dedalo's planted bankruptcy: premium of its XBQ perpetual's last price over the index (top) and funding of each 8-hour period (bottom), 5 to 11 November 2022.* Two panels sharing the time axis and a highlighted vertical line on 8 November at 12:00, when withdrawals are suspended. Top, dedalo's perpetual trades at the index until then and afterwards sinks to 17% below it on the 11th. Bottom, funding is 1 basis point or near zero before and turns deeply negative after, from −20 to −50 basis points per period, reaching the −50 cap.

The figure follows the whole episode: the `dedalo` perpetual glued to the index until the suspension and a discount
that reaches 17% on the 11th; funding, from one basis point before to between −20 and −50 basis points per period
after, with one period at the −50 basis point cap. Nothing in the prices or the funding of the previous days gave a
warning. What is left of a cash-and-carry depending on how the capital had been allocated?

```python
L = 3
capital = 1 + 1 / L            # per unit of notional: spot + margin
retirado = ded["tasa_funding"][:"2022-10-31"].sum()  # at month end
c = {e: fu[(fu["exchange"] == e) & (fu["activo"] == "XBQ")]
     .set_index("ts")["tasa_funding"][:hasta].sum()
     for e in ["alfa", "boreal", "cenit"]}
escenarios = {
    "all on dedalo, no withdrawals": 0.0,
    "all on dedalo, withdrawing every month": retirado,
    "a quarter on each exchange": (3 * capital + sum(c.values())
                                   + retirado) / 4,
    "all on alfa": capital + c["alfa"],
}
for k, v in escenarios.items():
    print(f"{k:40s} {v / capital:6.2f} times the capital")
riesgo = (c_ded - c_alfa) / anos / capital
print(f"dedalo premium on capital: {100 * riesgo:.1f}% a year")
```
```output
all on dedalo, no withdrawals              0.00 times the capital
all on dedalo, withdrawing every month     0.52 times the capital
a quarter on each exchange                 1.22 times the capital
all on alfa                                1.44 times the capital
dedalo premium on capital: 2.6% a year
```

The four figures are the final capital, as of November 11, 2022, per unit of initial capital, with the short at 3x and
without costs. With everything on `dedalo` and without withdrawing profits, zero: the spot, the margin and almost three
years of carry. If the carry was withdrawn at the end of each month, 0.52 remains, the carry taken out; the capital is
lost. Split equally across the four exchanges, 1.22: the quarter on `dedalo` is lost and the rest collects. Everything
on `alfa`, 1.44. The `dedalo` premium, 3.53 points of notional a year, is 2.6% a year of capital: it is the annual
probability of bankruptcy that the premium compensated if a bankruptcy destroys the capital deposited. Nobody could
estimate it from prices.

<aside class="callout" data-kind="riesgo">

**The real case, according to the regulators.** The civil complaint that the CFTC filed on December 13, 2022 in the
Southern District of New York against Samuel Bankman-Fried, FTX Trading and Alameda Research alleges that FTX customer
funds were accepted and held by Alameda, commingled with its own, and that Alameda had undisclosed advantages
programmed into the code: it was exempt from the “auto-liquidation” engine that closed the positions of the other
customers, it had a flag that let it trade without funds (“allow negative flag”) and a virtually unlimited line of
credit. According to the same complaint, on November 2, 2022 CoinDesk published Alameda's balance sheet, full of FTT,
the FTX token; on the 6th, Binance's CEO announced he would sell his FTT; withdrawal requests soared; on the 10th, FTX
halted trading and withdrawals, and on the 11th, 134 group companies filed for bankruptcy in the Delaware bankruptcy
court. The CFTC press release speaks of more than 8 billion USD of customer deposits lost. The SEC filed its own
complaint the same day, for defrauding FTX investors; it alleges, among other things, the undisclosed diversion of
customer funds to Alameda and that Alameda was exempt from key risk mitigation measures of the platform.

</aside>

For a carry strategy, the lesson is direct. The exchange is not neutral infrastructure: it is the counterparty of
everything deposited on it. Higher funding or basis on an exchange can be the signal that the market is asking it for
a premium for that risk. The defenses are those of any credit risk: limits per counterparty, periodic withdrawal of
profits, separate custody when the exchange offers it and exchanges with verifiable supervision and asset segregation
(lesson 3.7.5 covers the European framework).

## What this changes in a carry backtest

- **Carry net of the floor.** Separate the 10.95% set by the formula from the market premium: the latter is the one
  that narrows, and the one a strategy tries to capture.
- **Margin and liquidations of the short leg.** Simulate the margin with the intraday mark and a realistic top-up
  frequency; a cash-and-carry without margin is not the strategy that can be traded.
- **Costs per switch.** Four sides each time you enter and exit: a week of carry.
- **Lock in or float.** The quarterly removes funding uncertainty until expiry, but it has its own rolls and its own
  margin.
- **One counterparty per exchange.** A backtest with prices from an exchange that no longer exists includes its carry
  and not its bankruptcy if the universe is built with the exchanges still alive: it is survivorship bias (lesson
  2.5.1).

## Exercises

1. Repeat the short-leg leverage table for XEQ on `alfa` (2x, 3x and 5x, weekly rebalancing). What changes and why?

**Solution.**

```python
bq = h1[h1["activo"] == "XEQ"].set_index("ts")
fe = fu[(fu["exchange"] == "alfa") & (fu["activo"] == "XEQ")]
fe = fe.set_index("ts")["tasa_funding"]
anual_e = fe.sum() / ((fe.index[-1] - fe.index[0]).days / 365.25)
filas = []
for L in (2, 3, 5):
    g = bq.groupby(pd.Grouper(freq="7D"))
    liq = g["apertura"].first() * (1 + 1 / L) / (1 + MMR)
    filas.append({"apal_corto": L,
                  "rend_capital_pct": 100 * anual_e / (1 + 1 / L),
                  "liq_semanal": int((g["mark_maximo"].max() >= liq)
                                     .sum())})
pd.DataFrame(filas).set_index("apal_corto").round(1)
```
```output
            rend_capital_pct  liq_semanal
apal_corto
2                       15.1            0
3                       17.0            5
5                       18.9           25
```

With XEQ the average carry on `alfa` is higher (the return on capital rises to 15.1% with 2x and to 17.0% with 3x),
but XEQ is more volatile than XBQ and the short leg is liquidated much more often: 5 weeks at 3x (versus 1 for XBQ) and
25 at 5x. The reasonable leverage of the short leg depends on the asset's volatility, not on the carry: with XEQ, 2x
yields more (15.1%) than XBQ at 3x and has no liquidation at all in six years.

2. Compute the annual result of a funding differential long the `cenit` perpetual and short the `boreal` one (XBQ,
   same notional), deducting one entry and one exit per year at 5 basis points per side. Is it worth the capital and
   the two counterparties?

**Solution.**

```python
neto = diferencial.groupby(diferencial.index.year).sum() * 100
neto = neto - 4 * 5 / 1e4 * 100    # enter and exit once a year
neto.round(2).to_dict()
```
```output
{2020: 4.76, 2021: 3.24, 2022: 2.44, 2023: 2.28, 2024: 2.1, 2025: 1.53}
```

The differential net of one entry and one exit per year goes from 4.76 points of notional in 2020 to 1.53 in 2025. But
the capital is not the notional: each leg needs its own margin on its exchange, with 3x on both 67% of notional, so in
2025 it yields about 2.3% on capital, well below a simple cash-and-carry with the short leg at 3x (11.6% on average on
`alfa`). In addition, there are two counterparties and two margins to monitor, and if one of the legs is liquidated or
its exchange fails, a directional position is left on the other. It only makes sense as a complement to a carry
portfolio already spread across exchanges, not as a strategy of its own.

3. Apply the rule “lock in the basis if it is larger than the funding of the previous 90 days” to the six exchange and
   asset pairs that survive. Does it always beat the perpetual alone? What would make you distrust the result on real
   data?

**Solution.**

```python
filas = []
for (e, ac), fut in ft[ft["exchange"] != "dedalo"].groupby(
        ["exchange", "activo"]):
    fund = (fu[(fu["exchange"] == e) & (fu["activo"] == ac)]
            .set_index("ts")["tasa_funding"])
    q2 = trimestres(fut, fund)
    fija = q2["fijado"] > q2["funding_previo"]
    filas.append({"exchange": e, "activo": ac,
                  "fijado": q2["fijado"].mean(),
                  "perpetuo": q2["funding"].mean(),
                  "regla": np.where(fija, q2["fijado"],
                                    q2["funding"]).mean(),
                  "fija_pct": 100 * fija.mean()})
pd.DataFrame(filas).set_index(["exchange", "activo"]).round(2)
```
```output
                 fijado  perpetuo  regla  fija_pct
exchange activo
alfa     XBQ       3.97      3.97   5.14     43.48
         XEQ       3.92      5.30   6.55     43.48
boreal   XBQ       4.44      4.38   5.33     52.17
         XEQ       4.18      5.69   7.04     21.74
cenit    XBQ       3.13      3.62   4.42     26.09
         XEQ       3.58      4.88   6.26     21.74
```

On all six pairs, the rule beats the perpetual alone: from 3.97% to 5.14% per quarter on XBQ on `alfa`, and between
0.8 and 1.4 points on the others; it locks in the basis in between 22% and 52% of the quarters depending on the pair.
On XEQ, always locking in would do worse than the perpetual (3.92% versus 5.30% on `alfa`): the basis in the data only
prices in 0.8 times the funding, and with XEQ's high funding that difference weighs. In the data it has a known
explanation: the basis carries noise of its own that does not anticipate the next funding, so choosing the larger of
the two at opening captures that noise without looking at the future. On real data one should distrust it for several
reasons: there is no guarantee that the noise of the basis is independent of upcoming funding (it may price in
information that past funding does not have), 23 quarters per pair are few observations, the rule was chosen after
seeing the data (lesson 2.5.1) and the quarterly has costs and risks of its own (margin until expiry, lower liquidity
than the perpetual).

## Self-assessment

1. In calm markets, with the perpetual's premium inside the band, what does the short of a cash-and-carry collect on an exchange that uses Binance's formula?

   - A. The fixed interest of 0.01% per period, almost 11% a year of notional: a convention of the formula, not a market price
   - B. Nothing: without a premium there is no funding
   - C. The dollar interest rate
   - D. Half the premium

   *Answer A: The fixed interest of 0.01% per period, almost 11% a year of notional: a convention of the formula, not a market price.* With the premium between −4 and +6 basis points, F = P + (I − P) = I = 0.01% per period: 0.0001 × 3 × 365 = 10.95% a year. Since 2022 the carry of the three surviving exchanges stays close to that floor; what narrows is the bullish premium, with a half-life of 2.5 years in the data.

2. The short leg of the XBQ cash-and-carry on alfa is held at 10x and rebalanced every week. What does the data say?

   - A. That it is the best option: 14.1% on capital with no risk
   - B. That there are no liquidations because the position is hedged
   - C. That leverage does not change the return
   - D. That the return on capital rises from 11.6% (3x) to 14.1%, but the mark would have liquidated the short in 71 of 314 weeks, leaving the spot unhedged

   *Answer D: That the return on capital rises from 11.6% (3x) to 14.1%, but the mark would have liquidated the short in 71 of 314 weeks, leaving the spot unhedged.* The hedge offsets the PnL between the two legs, but each leg has its own margin. A 9% or 10% rise within the week liquidates the 10x short even if the spot has gained the same. More leverage yields a little more on capital and multiplies the liquidations.

3. Basis locked in with the quarterly and funding collected by the perpetual in the same quarter: over 23 XBQ quarters on alfa, how do they relate?

   - A. The basis always wins
   - B. Funding always wins
   - C. The same mean (3.97% per quarter) and a correlation of only 0.24: each quarter one beats the other by several points
   - D. They are identical by arbitrage

   *Answer C: The same mean (3.97% per quarter) and a correlation of only 0.24: each quarter one beats the other by several points.* The basis prices in the expected funding plus a premium, with noise of its own. Locking it in removes the funding uncertainty, but it does not win on average. Choosing the larger of the two at opening (the basis or the funding of the previous 90 days) gives 5.14%: in the data, the noise of the basis does not predict the next funding, and the choice can be made without looking at the future.

4. boreal pays 3.03 points a year more than alfa in 2020 and 1.05 in 2022, even though the planted difference in its premium is constant. Why does it narrow?

   - A. Because of the bankruptcy of dedalo
   - B. Because the formula fixes funding at 0.01% while the premium is inside the band: a slightly different premium only shows when it leaves the band, and in quiet years it almost never does
   - C. Because boreal lowered its fees
   - D. Because of rounding

   *Answer B: Because the formula fixes funding at 0.01% while the premium is inside the band: a slightly different premium only shows when it leaves the band, and in quiet years it almost never does.* In 71.4% of the periods boreal and cenit pay exactly the same, the band's basis point. The differential between exchanges lives in the weeks of euphoria, which in the data (and, according to He, Manela, Ross and von Wachter, in real markets) are less and less profitable.

5. dedalo paid 3.53 points a year more funding than alfa until its bankruptcy. With the short leg at 3x, what annual probability of bankruptcy did that premium compensate?

   - A. None: the premium was free
   - B. About 2.6% a year: the premium on capital; a bankruptcy takes the entire capital deposited on the exchange
   - C. 35%
   - D. 0.01%

   *Answer B: About 2.6% a year: the premium on capital; a bankruptcy takes the entire capital deposited on the exchange.* With capital of 1 + 1/3 per unit of notional, 3.53 points of notional are 2.6% of capital a year. If bankruptcy destroys all the capital deposited, the premium compensates a probability of bankruptcy of that order, which no price data allowed anyone to estimate before November 8.

## Key points

- The perpetual's carry has two parts: the floor of almost 11% a year set by the formula's interest term and a market premium. In the data the bullish premium narrows with a half-life of 2.53 years (planted: 2.5); since 2022 the carry stays close to the floor.
- The short leg needs margin and can be liquidated even if the position is hedged: with 3x and weekly rebalancing, 11.6% a year on capital and one liquidation in six years; with 10x, 14.1% and 71 liquidated weeks.
- The quarterly's basis locks in the carry until expiry. Over 23 quarters, the locked-in mean (3.97%) is the same as the funding collected, with a correlation of 0.24: locking in removes uncertainty, it does not add return.
- Funding differentials between exchanges are eaten by the clamp band (71.4% of periods pay the same) and narrow every year. Price dislocations are rare, brief and require inventory on both exchanges.
- dedalo's premium (3.53 points a year of notional) paid for a bankruptcy risk of about 2.6% a year of capital. With everything on dedalo, everything was lost; spread across four exchanges, a quarter of the capital.
- At FTX, according to the CFTC and SEC complaints, customer funds were diverted to Alameda, which was exempt from the liquidation engine: counterparty risk does not show in prices until it is too late.

## Resources

### Documentation

- [CFTC: complaint against Samuel Bankman-Fried, FTX Trading and Alameda Research (S.D.N.Y., December 13, 2022, PDF)](https://www.cftc.gov/media/7986/enfftxtradingcomplaint121322/download) · cftc.gov
- [CFTC: press release 8638-22 on the complaint (December 13, 2022)](https://www.cftc.gov/PressRoom/PressReleases/8638-22) · cftc.gov
- [SEC: press release 2022-219, SEC Charges Samuel Bankman-Fried with Defrauding Investors (December 13, 2022)](https://www.sec.gov/news/press-release/2022-219) · sec.gov
- [Binance: Introduction to Binance Futures Funding Rates](https://www.binance.com/en/support/faq/introduction-to-binance-futures-funding-rates-360033525031) · binance.com
- [He, Manela, Ross and von Wachter: Fundamentals of Perpetual Futures (arXiv 2212.06888)](https://arxiv.org/abs/2212.06888) · arxiv.org

### Data

- [Level 3 data: crypto quarterly futures, daily snapshot (Parquet)](https://pythonparatrading.com/curso/datos/nivel-3/cripto3_futuros.parquet) · Download · cripto3_futuros.parquet
- [Level 3 data: daily close by exchange with withdrawals open or not (Parquet)](https://pythonparatrading.com/curso/datos/nivel-3/cripto3_diario.parquet) · Download · cripto3_diario.parquet
- [Level 3 data: exchange profiles and timeline of the dedalo bankruptcy (CSV)](https://pythonparatrading.com/curso/datos/nivel-3/cripto3_exchanges.csv) · Download · cripto3_exchanges.csv

Previous lesson: [3.7.1 · Perpetuals: funding mechanics, mark price and liquidations](https://pythonparatrading.com/en/python-trading-course/level-3/perpetual-futures-funding-mark-price-liquidations/)

Next lesson: [3.7.3 · Crypto options, on-chain data and DeFi](https://pythonparatrading.com/en/python-trading-course/level-3/crypto-options-on-chain-defi/)
